Index: branches/5.2.x/core/admin_templates/languages/email_message_edit.tpl =================================================================== diff -u -N -r14244 -r15222 --- branches/5.2.x/core/admin_templates/languages/email_message_edit.tpl (.../email_message_edit.tpl) (revision 14244) +++ branches/5.2.x/core/admin_templates/languages/email_message_edit.tpl (.../email_message_edit.tpl) (revision 15222) @@ -67,13 +67,14 @@ - + - + - + + Index: branches/5.2.x/core/units/email_events/email_events_event_handler.php =================================================================== diff -u -N -r15215 -r15222 --- branches/5.2.x/core/units/email_events/email_events_event_handler.php (.../email_events_event_handler.php) (revision 15215) +++ branches/5.2.x/core/units/email_events/email_events_event_handler.php (.../email_events_event_handler.php) (revision 15222) @@ -1,6 +1,6 @@ SetDBField('Headers', $this->Application->ConfigValue('Smtp_DefaultHeaders')); + $this->setRequired($event); } /** @@ -152,17 +153,17 @@ */ function OnFrontOnly($event) { - if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { + if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) { $event->status = kEvent::erFAIL; - return ; + return; } $ids = implode(',', $this->StoreSelectedIDs($event)); $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); - $sql = 'UPDATE '.$table_name.' + $sql = 'UPDATE ' . $table_name . ' SET FrontEndOnly = 1 - WHERE EventId IN ('.$ids.')'; + WHERE EventId IN (' . $ids . ')'; $this->Conn->Query($sql); $this->clearSelectedIDs($event); @@ -225,58 +226,58 @@ function OnProcessEmailQueue($event) { $deliver_count = $event->getEventParam('deliver_count'); - if ($deliver_count === false) { + if ( $deliver_count === false ) { $deliver_count = $this->Application->ConfigValue('MailingListSendPerStep'); - if ($deliver_count === false) { + if ( $deliver_count === false ) { $deliver_count = 10; // 10 emails per script run (if not specified directly) } } $processing_type = $this->Application->GetVar('type'); - if ($processing_type = 'return_progress') { + if ( $processing_type = 'return_progress' ) { $email_queue_progress = $this->Application->RecallVar('email_queue_progress'); - if ($email_queue_progress === false) { + if ( $email_queue_progress === false ) { $emails_sent = 0; $sql = 'SELECT COUNT(*) FROM ' . TABLE_PREFIX . 'EmailQueue WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')'; $total_emails = $this->Conn->GetOne($sql); - $this->Application->StoreVar('email_queue_progress', $emails_sent.':'.$total_emails); + $this->Application->StoreVar('email_queue_progress', $emails_sent . ':' . $total_emails); } else { list ($emails_sent, $total_emails) = explode(':', $email_queue_progress); } } $sql = 'SELECT * - FROM '.TABLE_PREFIX.'EmailQueue + FROM ' . TABLE_PREFIX . 'EmailQueue WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ') LIMIT 0,' . $deliver_count; $messages = $this->Conn->Query($sql); $message_count = count($messages); - if (!$message_count) { + if ( !$message_count ) { // no messages left to send in queue - if ($processing_type = 'return_progress') { + if ( $processing_type = 'return_progress' ) { $this->Application->RemoveVar('email_queue_progress'); $this->Application->Redirect($this->Application->GetVar('finish_template')); } - return ; + return; } $mailing_list_helper = $this->Application->recallObject('MailingListHelper'); /* @var $mailing_list_helper MailingListHelper */ $mailing_list_helper->processQueue($messages); - if ($processing_type = 'return_progress') { + if ( $processing_type = 'return_progress' ) { $emails_sent += $message_count; - if ($emails_sent >= $total_emails) { + if ( $emails_sent >= $total_emails ) { $this->Application->RemoveVar('email_queue_progress'); $this->Application->Redirect($this->Application->GetVar('finish_template')); } - $this->Application->StoreVar('email_queue_progress', $emails_sent.':'.$total_emails); + $this->Application->StoreVar('email_queue_progress', $emails_sent . ':' . $total_emails); $event->status = kEvent::erSTOP; echo ($emails_sent / $total_emails) * 100; } @@ -296,7 +297,7 @@ $options = Array (); foreach ($this->Application->ModuleInfo as $module_name => $module_info) { - if ($module_name == 'In-Portal') { + if ( $module_name == 'In-Portal' ) { continue; } @@ -307,7 +308,7 @@ $fields['Module']['options'] = $options; $this->Application->setUnitOption($event->Prefix, 'Fields', $fields); - if ($this->Application->GetVar('regional')) { + if ( $this->Application->GetVar('regional') ) { $this->Application->setUnitOption($event->Prefix, 'PopulateMlFields', true); } } @@ -342,8 +343,8 @@ $object = $event->getObject(); /* @var $object kDBItem */ - if (!$this->Application->isDebugMode(false)) { - if ($object->GetDBField('AllowChangingRecipient')) { + if ( !$this->Application->isDebugMode(false) ) { + if ( $object->GetDBField('AllowChangingRecipient') ) { $object->SetDBField('RecipientType', EmailEvent::RECIPIENT_TYPE_TO); } else { @@ -365,6 +366,8 @@ $xml = $minput_helper->prepareMInputXML($records, Array ('Tag', 'Replacement')); $object->SetDBField('ReplacementTagsXML', $xml); + + $this->setRequired($event); } /** @@ -381,28 +384,28 @@ $this->_validateEmailTemplate($object); // validate sender and recipient addresses - if ($object->GetDBField('CustomSender')) { + if ( $object->GetDBField('CustomSender') ) { $this->_validateAddress($event, 'Sender'); } $this->_validateAddress($event, 'Recipient'); - if (!$this->Application->isDebugMode(false)) { + if ( !$this->Application->isDebugMode(false) ) { // only allow to enable/disable event while in debug mode $to_restore = Array ('Enabled', 'AllowChangingSender', 'AllowChangingRecipient'); - if (!$object->GetOriginalField('AllowChangingSender')) { + if ( !$object->GetOriginalField('AllowChangingSender') ) { $to_restore = array_merge($to_restore, Array ('CustomSender', 'SenderName', 'SenderAddressType', 'SenderAddress')); } - if (!$object->GetOriginalField('AllowChangingRecipient')) { - $to_restore = array_merge($to_restore, Array ('CustomRecipient'/*, 'Recipients'*/)); + if ( !$object->GetOriginalField('AllowChangingRecipient') ) { + $to_restore = array_merge($to_restore, Array ('CustomRecipient' /*, 'Recipients'*/)); } // prevent specific fields from editing foreach ($to_restore as $restore_field) { $original_value = $object->GetOriginalField($restore_field); - if ($object->GetDBField($restore_field) != $original_value) { + if ( $object->GetDBField($restore_field) != $original_value ) { $object->SetDBField($restore_field, $original_value); } } @@ -414,10 +417,10 @@ /* @var $minput_helper MInputHelper */ $replacement_tags = Array (); - $records = $minput_helper->parseMInputXML( $object->GetDBField('ReplacementTagsXML') ); + $records = $minput_helper->parseMInputXML($object->GetDBField('ReplacementTagsXML')); foreach ($records as $record) { - $replacement_tags[ trim($record['Tag']) ] = trim($record['Replacement']); + $replacement_tags[trim($record['Tag'])] = trim($record['Replacement']); } $object->SetDBField('ReplacementTags', $replacement_tags ? serialize($replacement_tags) : NULL); @@ -427,18 +430,38 @@ $object->SetDBField('LastChanged_date', TIMENOW); $object->SetDBField('LastChanged_time', TIMENOW); } + + $this->setRequired($event); } /** + * Dynamically changes required fields + * + * @param kEvent $event + * @return void + * @access protected + */ + protected function setRequired(kEvent $event) + { + $object = $event->getObject(); + /* @var $object kDBItem */ + + $language_prefix = 'l' . $this->Application->GetVar('m_lang') . '_'; + + $object->setRequired($language_prefix . 'HtmlBody', !$object->GetField('PlainTextBody')); + $object->setRequired($language_prefix . 'PlainTextBody', !$object->GetField('HtmlBody')); + } + + /** * Checks, that at least one of phrase's translations was changed * * @param kDBItem $object * @return bool */ - function translationChanged(&$object) + function translationChanged($object) { - $changed_fields = array_keys( $object->GetChangedFields() ); - $translation_fields = Array ('Subject', 'Body'); + $changed_fields = array_keys($object->GetChangedFields()); + $translation_fields = Array ('Subject', 'HtmlBody', 'PlainTextBody'); foreach ($changed_fields as $changed_field) { $changed_field = preg_replace('/^l[\d]+_/', '', $changed_field); @@ -466,14 +489,14 @@ $object->setRequired($field_prefix . 'Address', $address_type > 0); $address = $object->GetDBField($field_prefix . 'Address'); - if (!$address) { + if ( !$address ) { // don't validate against empty address - return ; + return; } switch ($address_type) { case EmailEvent::ADDRESS_TYPE_EMAIL: - if (!preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $address)) { + if ( !preg_match('/^(' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . ')$/i', $address) ) { $object->SetError($field_prefix . 'Address', 'invalid_email'); } break; @@ -482,7 +505,7 @@ $sql = 'SELECT PortalUserId FROM ' . TABLE_PREFIX . 'Users WHERE Username = ' . $this->Conn->qstr($address); - if (!$this->Conn->GetOne($sql)) { + if ( !$this->Conn->GetOne($sql) ) { $object->SetError($field_prefix . 'Address', 'invalid_user'); } break; @@ -491,7 +514,7 @@ $sql = 'SELECT GroupId FROM ' . TABLE_PREFIX . 'UserGroups WHERE Name = ' . $this->Conn->qstr($address); - if (!$this->Conn->GetOne($sql)) { + if ( !$this->Conn->GetOne($sql) ) { $object->SetError($field_prefix . 'Address', 'invalid_group'); } break; @@ -589,21 +612,26 @@ /** * Validates subject and body fields of Email template + * * @param kDBItem $object + * @return void + * @access protected */ - function _validateEmailTemplate(&$object) + protected function _validateEmailTemplate($object) { $this->parseField($object, 'Subject'); - $this->parseField($object, 'Body'); + $this->parseField($object, 'HtmlBody'); + $this->parseField($object, 'PlainTextBody'); } /** * Parses contents of given object field and sets error, when invalid in-portal tags found * @param kDBItem $object * @param string $field * @return void + * @access protected */ - function parseField(&$object, $field) + protected function parseField($object, $field) { $this->Application->InitParser(); Index: branches/5.2.x/core/kernel/utility/email.php =================================================================== diff -u -N -r15215 -r15222 --- branches/5.2.x/core/kernel/utility/email.php (.../email.php) (revision 15215) +++ branches/5.2.x/core/kernel/utility/email.php (.../email.php) (revision 15222) @@ -1,6 +1,6 @@ emailEvent->GetDBField('MessageType') == 'html'; - $message_body = $this->_getMessageBody($is_html); + $html_message_body = $this->_getMessageBody(true); + $plain_message_body = $this->_getMessageBody(false); - if ( $message_body === false ) { + if ( $html_message_body === false && $plain_message_body === false ) { + trigger_error('Message template is empty (maybe after parsing).', E_USER_WARNING); + return false; } - $this->sender->CreateTextHtmlPart($message_body, $is_html); + if ( $html_message_body !== false ) { + $this->sender->CreateTextHtmlPart($html_message_body, true); + } + + if ( $plain_message_body !== false ) { + $this->sender->CreateTextHtmlPart($plain_message_body, false); + } + $this->_changeLanguage(true); // 3. set log @@ -682,15 +691,14 @@ $design_key = $is_html ? 'html' : 'text'; if ( !isset($design_templates[$design_key]) ) { - $primary_language_id = $this->Application->GetDefaultLanguageId(); + $footer_email = $this->Application->recallObject('emailevents.footer', null, Array ('skip_autoload' => true)); + /* @var $footer_email kDBItem */ - $sql = 'SELECT IF(l' . $this->params['language_id'] . '_Body <> "", l' . $this->params['language_id'] . '_Body, l' . $primary_language_id . '_Body) - FROM ' . $this->emailEvent->TableName . ' - WHERE Event = "COMMON.FOOTER"'; - $footer = $this->Conn->GetOne($sql); + $footer_email->Load('COMMON.FOOTER', 'Event'); + $footer = $footer_email->GetField($is_html ? 'HtmlBody' : 'PlainTextBody'); - if ( !$is_html ) { - $footer = $this->sender->ConvertToText($footer); + if ( !$is_html && !$footer ) { + $footer = $this->sender->ConvertToText($footer_email->GetField('HtmlBody')); } $design_templates[$design_key] = '$body'; @@ -710,25 +718,22 @@ * @return bool|string * @access protected */ - protected function _getMessageBody($is_html = true) + protected function _getMessageBody($is_html = false) { - $message_body = $this->emailEvent->GetField('Body'); + $message_body = $this->emailEvent->GetField($is_html ? 'HtmlBody' : 'PlainTextBody'); - if ( !trim($message_body) ) { - trigger_error('Message template is empty', E_USER_WARNING); - - return false; + if ( !trim($message_body) && !$is_html ) { + // no plain text part available -> make it from html part then + $message_body = $this->sender->ConvertToText($this->emailEvent->GetField('HtmlBody')); } - $message_body = $this->_applyMessageDesign($message_body, $is_html); - if ( !trim($message_body) ) { - trigger_error('Message template is empty after parsing', E_USER_WARNING); - return false; } - return $message_body; + $message_body = $this->_applyMessageDesign($message_body, $is_html); + + return trim($message_body) ? $message_body : false; } /** Index: branches/5.2.x/core/admin_templates/regional/email_messages_edit.tpl =================================================================== diff -u -N -r14572 -r15222 --- branches/5.2.x/core/admin_templates/regional/email_messages_edit.tpl (.../email_messages_edit.tpl) (revision 14572) +++ branches/5.2.x/core/admin_templates/regional/email_messages_edit.tpl (.../email_messages_edit.tpl) (revision 15222) @@ -21,19 +21,19 @@ ) ); a_toolbar.AddButton( new ToolBarSeparator('sep1') ); - + a_toolbar.AddButton( new ToolBarButton('prev', '', function() { go_to_id('emailevents', ''); } )); - + a_toolbar.AddButton( new ToolBarButton('next', '', function() { go_to_id('emailevents', ''); } )); - + a_toolbar.Render(); - + a_toolbar.HideButton('prev'); a_toolbar.HideButton('next'); @@ -64,11 +64,11 @@ - - + + Index: branches/5.2.x/core/install/upgrades.php =================================================================== diff -u -N -r15176 -r15222 --- branches/5.2.x/core/install/upgrades.php (.../upgrades.php) (revision 15176) +++ branches/5.2.x/core/install/upgrades.php (.../upgrades.php) (revision 15222) @@ -1,6 +1,6 @@ Application->recallObject('EmailMessageHelper'); /* @var $email_message_helper EmailMessageHelper */ - foreach ($languages as $language_id) { $sql = 'SELECT EmailMessageId, Template, EventId FROM ' . TABLE_PREFIX . 'EmailMessage WHERE LanguageId = ' . $language_id; $translations = $this->Conn->Query($sql, 'EventId'); foreach ($translations as $event_id => $translation_data) { - $parsed = $email_message_helper->parseTemplate($translation_data['Template']); + $parsed = $email_message_helper->parseTemplate($translation_data['Template'], 'html'); $fields_hash = Array ( 'l' . $language_id . '_Subject' => $parsed['Subject'], - 'l' . $language_id . '_Body' => $parsed['Body'], + 'l' . $language_id . '_Body' => $parsed['HtmlBody'], ); - if ($parsed['Headers']) { + if ( $parsed['Headers'] ) { $fields_hash['Headers'] = $parsed['Headers']; } @@ -2022,4 +2021,64 @@ $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'PageContent', 'PageId = ' . $page_id); } } + + /** + * Update to 5.2.0-B3; Introduces separate field for plain-text e-mail event translations + * + * @param string $mode when called mode {before, after) + */ + public function Upgrade_5_2_0_B3($mode) + { + if ( $mode == 'before' ) { + $this->_renameTables('to'); + } + + if ( $mode == 'after' ) { + $id_field = $this->Application->getUnitOption('emailevents', 'IDField'); + $table_name = $this->Application->getUnitOption('emailevents', 'TableName'); + $fields = $this->Conn->Query('DESCRIBE ' . $table_name, 'Field'); + + if ( !isset($fields['l1_Body']) ) { + // column dropped - nothing to convert anymore + return; + } + + $ml_helper = $this->Application->recallObject('kMultiLanguageHelper'); + /* @var $ml_helper kMultiLanguageHelper */ + + $languages = $ml_helper->getLanguages(); + $ml_helper->createFields('emailevents'); + + $sql = 'SELECT * + FROM ' . $table_name; + $email_events = $this->Conn->Query($sql); + + // 1. move data to new columns + foreach ($email_events as $email_event) { + $fields_hash = Array (); + $translation_field = $email_event['MessageType'] == 'html' ? 'HtmlBody' : 'PlainTextBody'; + + foreach ($languages as $language_id) { + $fields_hash['l' . $language_id . '_' . $translation_field] = $email_event['l' . $language_id . '_Body']; + } + + if ( $fields_hash ) { + $this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $email_event[$id_field]); + } + } + + // 2. drop old columns + $drops = Array ('DROP COLUMN MessageType'); + + foreach ($languages as $language_id) { + $lang_field = 'l' . $language_id . '_Body'; + + if ( isset($fields[$lang_field]) ) { + $drops[] = 'DROP COLUMN ' . $lang_field; + } + } + + $this->Conn->Query('ALTER TABLE ' . $table_name . ' ' . implode(', ', $drops)); + } + } } \ No newline at end of file Index: branches/5.2.x/core/units/helpers/language_import_helper.php =================================================================== diff -u -N -r15158 -r15222 --- branches/5.2.x/core/units/helpers/language_import_helper.php (.../language_import_helper.php) (revision 15158) +++ branches/5.2.x/core/units/helpers/language_import_helper.php (.../language_import_helper.php) (revision 15222) @@ -1,6 +1,6 @@ node. There are -* two more nodes PHRASES and EVENTS for phrase and email event translations. -* -* v2 -* ========== -* All data, that will end up in Language table is now attributes of LANGUAGE node -* and is name exactly as field name, that will be used to store that data. -* -* v4 -* ========== -* Hint & Column translation added to each phrase translation -*/ + * Language pack format version description + * + * v1 + * ========== + * All language properties are separate nodes inside node. There are + * two more nodes PHRASES and EVENTS for phrase and email event translations. + * + * v2 + * ========== + * All data, that will end up in Language table is now attributes of LANGUAGE node + * and is name exactly as field name, that will be used to store that data. + * + * v4 + * ========== + * Hint & Column translation added to each phrase translation + * + * v5 + * ========== + * Use separate xml nodes for subject, headers, html & plain translations + * + */ defined('FULL_PATH') or die('restricted access!'); @@ -101,6 +106,7 @@ var $_exportLimits = Array ( 'phrases' => false, 'emailevents' => false, + 'country-state' => false, ); /** @@ -115,7 +121,7 @@ * * @var int */ - var $_latestVersion = 4; + var $_latestVersion = 5; /** * Prefix-based serial numbers, that should be changed after import is finished @@ -223,9 +229,6 @@ $export_fields = $this->_getExportFields(); - $email_message_helper = $this->Application->recallObject('EmailMessageHelper'); - /* @var $email_message_helper EmailMessageHelper */ - // get languages $sql = 'SELECT * FROM ' . $this->Application->getUnitOption('lang','TableName') . ' @@ -271,25 +274,36 @@ ORDER BY `Event`, `Type`'; $events = $this->Conn->Query($sql, 'EventId'); - if (in_array('Core', $module_ids)) { + if ( in_array('Core', $module_ids) ) { + if ($this->_exportLimits['country-state']) { + $escaped_countries = $this->Conn->qstrArray($this->_exportLimits['country-state']); + $limit_where = '`IsoCode` IN (' . implode(',', $escaped_countries) . ')'; + } + else { + $limit_where = 'TRUE'; + } + + $country_table = $this->Application->getUnitOption('country-state', 'TableName'); + // countries $sql = 'SELECT * - FROM ' . $this->Application->getUnitOption('country-state', 'TableName') . ' - WHERE Type = ' . DESTINATION_TYPE_COUNTRY . ' + FROM ' . $country_table . ' + WHERE Type = ' . DESTINATION_TYPE_COUNTRY . ' AND ' . $limit_where . ' ORDER BY `IsoCode`'; $countries = $this->Conn->Query($sql, 'CountryStateId'); // states - $sql = 'SELECT * - FROM ' . $this->Application->getUnitOption('country-state', 'TableName') . ' - WHERE Type = ' . DESTINATION_TYPE_STATE . ' - ORDER BY `IsoCode`'; + $sql = 'SELECT state.* + FROM ' . $country_table . ' state + JOIN ' . $country_table . ' country ON country.CountryStateId = state.StateCountryId + WHERE state.Type = ' . DESTINATION_TYPE_STATE . ' AND ' . str_replace('`IsoCode`', 'country.`IsoCode`', $limit_where) . ' + ORDER BY state.`IsoCode`'; $states = $this->Conn->Query($sql, 'CountryStateId'); foreach ($states as $state_id => $state_data) { $country_id = $state_data['StateCountryId']; - if (!array_key_exists('States', $countries[$country_id])) { + if ( !array_key_exists('States', $countries[$country_id]) ) { $countries[$country_id]['States'] = Array (); } @@ -364,30 +378,33 @@ if ($events) { $ret .= "\t\t" . '' . "\n"; - foreach ($events as $event_id => $event) { + foreach ($events as $event_data) { $fields_hash = Array ( - 'Headers' => $event['Headers'], - 'Subject' => $event['l' . $language_id . '_Subject'], - 'Body' => $event['l' . $language_id . '_Body'], + 'HEADERS' => $event_data['Headers'], + 'SUBJECT' => $event_data['l' . $language_id . '_Subject'], + 'HTMLBODY' => $event_data['l' . $language_id . '_HtmlBody'], + 'PLAINTEXTBODY' => $event_data['l' . $language_id . '_PlainTextBody'], ); - $template = $email_message_helper->buildTemplate($fields_hash); + $data = ''; - if (!$template) { - // email event is not translated on given language - continue; + foreach ($fields_hash as $xml_node => $xml_content) { + if ( $xml_content ) { + $data .= "\t\t\t\t" . '<' . $xml_node . '>' . $this->_exportConvert($xml_content) . '' . "\n"; + } } - $data = $this->_exportEncoding == 'base64' ? base64_encode($template) : ''; - $ret .= "\t\t\t" . '' . $data . ''."\n"; + if ( $data ) { + $ret .= "\t\t\t" . '' . "\n" . $data . "\t\t\t" . '' . "\n"; + } } $ret .= "\t\t" . '' . "\n"; } if (in_array('Core', $module_ids) && $countries) { $ret .= "\t\t" . '' . "\n"; - foreach ($countries as $country_id => $country_data) { + foreach ($countries as $country_data) { $translation = $country_data['l' . $language_id . '_Name']; if (!$translation) { @@ -433,6 +450,18 @@ } /** + * Converts string before placing into export file + * + * @param string $string + * @return string + * @access protected + */ + protected function _exportConvert($string) + { + return $this->_exportEncoding == 'base64' ? base64_encode($string) : ''; + } + + /** * Sets language pack encoding (not charset) used during export * * @param string $encoding @@ -890,36 +919,39 @@ foreach ($events as $event_node) { /* @var $event_node SimpleXMLElement */ + $message_type = (string)$event_node['MessageType']; $event_id = $this->_getEventId((string)$event_node['Event'], (int)$event_node['Type']); if ( !$event_id ) { continue; } - if ( $language_encoding == 'plain' ) { - $template = rtrim($event_node); - } - else { - $template = base64_decode($event_node); - } - - $parsed = $email_message_helper->parseTemplate($template); - $fields_hash = Array ( 'EventId' => $event_id, 'Event' => (string)$event_node['Event'], 'Type' => (int)$event_node['Type'], - 'MessageType' => (string)$event_node['MessageType'], ); + if ( $message_type == '' ) { + $parsed = $email_message_helper->parseTemplate($event_node, ''); + $parsed = array_map($language_encoding == 'plain' ? 'rtrim' : 'base64_decode', $parsed); + + } + else { + $template = $language_encoding == 'plain' ? rtrim($event_node) : base64_decode($event_node); + $parsed = $email_message_helper->parseTemplate($template, $message_type); + } + if ( array_key_exists($event_id, $other_translations) ) { $other_translations[$event_id]['l' . $language_id . '_Subject'] = $parsed['Subject']; - $other_translations[$event_id]['l' . $language_id . '_Body'] = $parsed['Body']; + $other_translations[$event_id]['l' . $language_id . '_HtmlBody'] = $parsed['HtmlBody']; + $other_translations[$event_id]['l' . $language_id . '_PlainTextBody'] = $parsed['PlainTextBody']; } else { $other_translations[$event_id] = Array ( 'l' . $language_id . '_Subject' => $parsed['Subject'], - 'l' . $language_id . '_Body' => $parsed['Body'], + 'l' . $language_id . '_HtmlBody' => $parsed['HtmlBody'], + 'l' . $language_id . '_PlainTextBody' => $parsed['PlainTextBody'], ); } Index: branches/5.2.x/core/units/phrases/phrases_config.php =================================================================== diff -u -N -r15116 -r15222 --- branches/5.2.x/core/units/phrases/phrases_config.php (.../phrases_config.php) (revision 15116) +++ branches/5.2.x/core/units/phrases/phrases_config.php (.../phrases_config.php) (revision 15222) @@ -1,6 +1,6 @@ Array ('type' => 'string', 'default' => ''), 'ExportEmailEvents' => Array ('type' => 'string', 'default' => ''), + 'ExportCountries' => Array ('type' => 'string', 'default' => ''), + 'ExportDataTypes' => Array ( + 'type' => 'string', + 'formatter' => 'kOptionsFormatter', 'options' => Array ('phrases' => 'la_opt_Phrases', 'emailevents' => 'la_opt_EmailEvents', 'country-state' => 'la_opt_Countries'), 'use_phrases' => 1, 'multiple' => 1, + 'default' => '|phrases|emailevents|country-state|' + ), ), 'Grids' => Array ( Index: branches/5.2.x/core/admin_templates/regional/languages_export.tpl =================================================================== diff -u -N -r15116 -r15222 --- branches/5.2.x/core/admin_templates/regional/languages_export.tpl (.../languages_export.tpl) (revision 15116) +++ branches/5.2.x/core/admin_templates/regional/languages_export.tpl (.../languages_export.tpl) (revision 15222) @@ -32,6 +32,7 @@ + @@ -47,6 +48,7 @@ + @@ -116,6 +118,7 @@ + Index: branches/5.2.x/core/units/phrases/phrases_event_handler.php =================================================================== diff -u -N -r15145 -r15222 --- branches/5.2.x/core/units/phrases/phrases_event_handler.php (.../phrases_event_handler.php) (revision 15145) +++ branches/5.2.x/core/units/phrases/phrases_event_handler.php (.../phrases_event_handler.php) (revision 15222) @@ -1,6 +1,6 @@ Special == 'import' || $event->Special == 'export' ) { $this->RemoveRequiredFields($object); - $object->setRequired(Array ('LangFile', 'PhraseType', 'Module')); + $object->setRequired(Array ('ExportDataTypes', 'LangFile', 'PhraseType', 'Module')); // allow multiple phrase types to be selected during import/export $object->SetFieldOption('PhraseType', 'type', 'string'); @@ -167,6 +167,12 @@ if ( $event->Special == 'export' || $event->Special == 'import' ) { $object->SetDBField('PhraseType', '|0|1|2|'); $object->SetDBField('Module', '|' . implode('|', array_keys($this->Application->ModuleInfo)) . '|'); + + $export_mode = $this->Application->GetVar('export_mode'); + + if ( $export_mode != 'lang' ) { + $object->SetDBField('ExportDataTypes', '|' . $export_mode . '|'); + } } } Index: branches/5.2.x/core/units/languages/languages_event_handler.php =================================================================== diff -u -N -r15145 -r15222 --- branches/5.2.x/core/units/languages/languages_event_handler.php (.../languages_event_handler.php) (revision 15145) +++ branches/5.2.x/core/units/languages/languages_event_handler.php (.../languages_event_handler.php) (revision 15222) @@ -1,6 +1,6 @@ Application->getUnitOption('emailevents', 'TableName') . ' SET l' . $dst_language . '_Subject = l' . $src_language . '_Subject, - l' . $dst_language . '_Body = l' . $src_language . '_Body'; + l' . $dst_language . '_HtmlBody = l' . $src_language . '_HtmlBody, + l' . $dst_language . '_PlainTextBody = l' . $src_language . '_PlainTextBody'; $this->Conn->Query($sql); } @@ -549,15 +550,26 @@ $language_import_helper->setExportEncoding('plain'); } + $data_types = Array ( + 'phrases' => 'ExportPhrases', + 'emailevents' => 'ExportEmailEvents', + 'country-state' => 'ExportCountries' + ); + $export_mode = $this->Application->GetVar('export_mode'); + $allowed_data_types = explode('|', substr($field_values['ExportDataTypes'], 1, -1)); if ( $export_mode == $event->Prefix ) { - $language_import_helper->setExportLimit('phrases', $field_values['ExportPhrases']); - $language_import_helper->setExportLimit('emailevents', $field_values['ExportEmailEvents']); + foreach ($data_types as $prefix => $export_limit_field) { + $export_limit = in_array($prefix, $allowed_data_types) ? $field_values[$export_limit_field] : '-'; + $language_import_helper->setExportLimit($prefix, $export_limit); + } } else { - $language_import_helper->setExportLimit($export_mode); - $language_import_helper->setExportLimit($export_mode == 'phrases' ? 'emailevents' : 'phrases', '-'); + foreach ($data_types as $prefix => $export_limit_field) { + $export_limit = in_array($prefix, $allowed_data_types) ? null : '-'; + $language_import_helper->setExportLimit($prefix, $export_limit); + } } $lang_ids = explode(',', $this->Application->RecallVar('export_language_ids')); @@ -621,7 +633,8 @@ // clean EmailEvents table $fields_hash = Array ( 'l' . $object->GetID() . '_Subject' => NULL, - 'l' . $object->GetID() . '_Body' => NULL, + 'l' . $object->GetID() . '_HtmlBody' => NULL, + 'l' . $object->GetID() . '_PlainTextBody' => NULL, ); $this->Conn->doUpdate($fields_hash, $this->Application->getUnitOption('emailevents', 'TableName'), 1); Index: branches/5.2.x/core/admin_templates/languages/email_message_settings.tpl =================================================================== diff -u -N -r14941 -r15222 --- branches/5.2.x/core/admin_templates/languages/email_message_settings.tpl (.../email_message_settings.tpl) (revision 14941) +++ branches/5.2.x/core/admin_templates/languages/email_message_settings.tpl (.../email_message_settings.tpl) (revision 15222) @@ -92,15 +92,14 @@ - + - Index: branches/5.2.x/core/units/email_events/email_events_config.php =================================================================== diff -u -N -r15116 -r15222 --- branches/5.2.x/core/units/email_events/email_events_config.php (.../email_events_config.php) (revision 15116) +++ branches/5.2.x/core/units/email_events/email_events_config.php (.../email_events_config.php) (revision 15222) @@ -1,6 +1,6 @@ 1, 'default' => null ), - 'Body' => Array ( + 'HtmlBody' => Array ( 'type' => 'string', 'formatter' => 'kMultiLanguage', 'db_type' => 'longtext', 'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!'), - 'required' => 1, 'default' => null + 'default' => null ), - 'MessageType' => Array ( + 'PlainTextBody' => Array ( 'type' => 'string', - 'formatter' => 'kOptionsFormatter', 'options' => Array ('text' => 'la_Text', 'html' => 'la_Html'), 'use_phrases' => 1, - 'not_null' => 1, 'required' => 1, 'default' => 'text' + 'formatter' => 'kMultiLanguage', 'db_type' => 'longtext', + 'error_msgs' => Array ('parsing_error' => '!la_error_ParsingError!'), + 'default' => null ), 'Enabled' => Array ( Index: branches/5.2.x/core/units/helpers/email_message_helper.php =================================================================== diff -u -N -r14748 -r15222 --- branches/5.2.x/core/units/helpers/email_message_helper.php (.../email_message_helper.php) (revision 14748) +++ branches/5.2.x/core/units/helpers/email_message_helper.php (.../email_message_helper.php) (revision 15222) @@ -1,6 +1,6 @@ '', 'Headers' => '', 'HtmlBody' => '', 'PlainTextBody' => ''); + + if ( $message_type == '' ) { + // this is v5+ e-mail event text as xml node + foreach ($ret as $field => $value) { + $node_name = strtoupper($field); + $ret[$field] = (string)$text->$node_name; + } + + return $ret; + } + $line_id = 1; - $ret = Array ('Subject' => '', 'Headers' => '', 'Body' => ''); $headers = Array(); $lines = explode("\n", $text); // "\n" is lost in process foreach ($lines as $line_id => $line) { - if (strlen(trim($line)) == 0 || ($line == '.')) { + if ( strlen(trim($line)) == 0 || ($line == '.') ) { break; } $parts = explode(':', $line, 2); - if (strtolower($parts[0]) == 'subject') { + + if ( strtolower($parts[0]) == 'subject' ) { $ret['Subject'] = trim($parts[1]); } else { @@ -48,7 +61,7 @@ $lines = array_slice($lines, $line_id + 1); // add "\n", that was lost before - $ret['Body'] = implode("\n", $lines); + $ret[$message_type == 'html' ? 'HtmlBody' : 'PlainTextBody'] = implode("\n", $lines); return $ret; } Index: branches/5.2.x/admin/system_presets/simple/email_events_emailevents.php =================================================================== diff -u -N -r15116 -r15222 --- branches/5.2.x/admin/system_presets/simple/email_events_emailevents.php (.../email_events_emailevents.php) (revision 15116) +++ branches/5.2.x/admin/system_presets/simple/email_events_emailevents.php (.../email_events_emailevents.php) (revision 15222) @@ -28,7 +28,7 @@ $hidden_fields = Array ( /*'EventId', 'Event', 'ReplacementTags', 'AllowChangingSender', 'CustomSender', 'SenderName', 'SenderAddressType', 'SenderAddress', 'AllowChangingRecipient', - 'CustomRecipient', 'Recipients', 'Subject', 'Body', 'Headers', 'MessageType', + 'CustomRecipient', 'Recipients', 'Subject', 'HtmlBody', 'PlainTextBody', 'Headers', 'Enabled', 'FrontEndOnly', 'Module', 'Description', 'Type'*/ ); @@ -42,7 +42,7 @@ $required_fields = Array ( /*'EventId',*/ 'Event', /*'ReplacementTags', 'AllowChangingSender', 'CustomSender', 'SenderName', 'SenderAddressType', 'SenderAddress', 'AllowChangingRecipient', - 'CustomRecipient', 'Recipients',*/ 'Subject', 'Body', /*'Headers',*/ 'MessageType', + 'CustomRecipient', 'Recipients',*/ 'Subject', /*'HtmlBody', 'PlainTextBody', 'Headers',*/ /*'Enabled', 'FrontEndOnly',*/ 'Module', /*'Description',*/ 'Type' ); Index: branches/5.2.x/core/install/english.lang =================================================================== diff -u -N -r15110 -r15222 --- branches/5.2.x/core/install/english.lang (.../english.lang) (revision 15110) +++ branches/5.2.x/core/install/english.lang (.../english.lang) (revision 15222) @@ -1,4 +1,4 @@ - + QWN0aXZl @@ -397,6 +397,8 @@ RXZlbnQ= RXhwaXJl RXhwb3J0IGNvbHVtbnM= + RXhwb3J0IFNwZWNpZmllZCBDb3VudHJpZXM= + RGF0YSBUeXBlcyB0byBFeHBvcnQ= RXhwb3J0IFNwZWNpZmllZCBFbWFpbCBFdmVudHM= RXhwb3J0IEZpbGVuYW1l RXhwb3J0IGZvcm1hdA== @@ -758,6 +760,7 @@ Q29tbWE= Q29tbWVudCBUZXh0 Q29va2llcw== + Q291bnRyaWVz Q291bnRyeQ== Q3JlYXRlZCBPbg== Q3VycmVudCBEb21haW4= @@ -773,6 +776,7 @@ RWRpdG9yJ3MgUGljaw== RS1tYWls RS1tYWlsIEJvZHk= + RS1tYWlsIEV2ZW50cw== RS1tYWlsIFN1YmplY3Q= RXZlcnlvbmU= RXhhY3Q= @@ -802,6 +806,7 @@ UGFydGlhbGx5IFByb2Nlc3NlZA== UGVuZGluZw== UGhvbmU= + TGFiZWxz UG9wdXAgV2luZG93 UHJvY2Vzc2Vk UHVibGlzaGVk @@ -1580,44 +1585,158 @@ VmFsaWQ= - U3ViamVjdDogTmV3IENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIC0gQWRkZWQKCllvdXIgc3VnZ2VzdGVkIGNhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGhhcyBiZWVuIGFkZGVkLg== - U3ViamVjdDogTmV3IENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIFN1Ym1pdHRlZCBieSBVc2VycwoKQSBjYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBhZGRlZC4= - U3ViamVjdDogU3VnZ2VzdGVkIENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGlzIFBlbmRpbmcKClRoZSBjYXRlZ29yeSB5b3Ugc3VnZ2VzdGVkICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGlzIHBlbmRpbmcgZm9yIGFkbWluaXN0cmF0aXZlIGFwcHJvdmFsLg0KDQpUaGFuayB5b3Uh - U3ViamVjdDogU3VnZ2VzdGVkIENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGlzIFBlbmRpbmcKCkEgY2F0ZWdvcnkgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaGFzIGJlZW4gYWRkZWQsIHBlbmRpbmcgeW91ciBjb25maXJtYXRpb24uICBQbGVhc2UgcmV2aWV3IHRoZSBjYXRlZ29yeSBhbmQgYXBwcm92ZSBvciBkZW55IGl0Lg== - U3ViamVjdDogQSBjYXRlZ29yeSBoYXMgYmVlbiBhcHByb3ZlZAoKWW91ciBzdWdnZXN0ZWQgY2F0ZWdvcnkgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaGFzIGJlZW4gYXBwcm92ZWQu - U3ViamVjdDogWW91ciBDYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBEZW5pZWQKCllvdXIgY2F0ZWdvcnkgc3VnZ2VzdGlvbiAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBkZW5pZWQu - U3ViamVjdDogQ29tbW9uIEZvb3RlciBUZW1wbGF0ZQoKPGJyLz48YnIvPg0KDQpTaW5jZXJlbHksPGJyLz48YnIvPg0KDQpXZWJzaXRlIGFkbWluaXN0cmF0aW9uLg== - U3ViamVjdDogTmV3IEVtYWlsIFJFUExZIFJlY2VpdmVkIGluICJGZWVkYmFjayBNYW5hZ2VyIiAoPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRmllbGQgbmFtZT0iRm9ybVN1Ym1pc3Npb25JZCIvPikKCk5ldyBFbWFpbCBSRVBMWSBSZWNlaXZlZCBpbiAmcXVvdDtGZWVkYmFjayBNYW5hZ2VyJnF1b3Q7LjxiciAvPg0KPGJyIC8+DQpPcmlnaW5hbCBGZWVkYmFja0lkOiA8aW5wMjpmb3Jtc3Vicy4taXRlbV9GaWVsZCBuYW1lPSJGb3JtU3VibWlzc2lvbklkIi8+IDxiciAvPg0KT3JpZ2luYWwgU3ViamVjdDogPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRm9ybUZpZWxkIHJvbGU9InN1YmplY3QiLz4gPGJyIC8+DQo8YnIgLz4NClBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIGluIG9yZGVyIHRvIHJldmlldyBhbmQgcmVwbHkgdG8gdGhlIHVzZXIu - U3ViamVjdDogTmV3IEVtYWlsIC0gRGVsaXZlcnkgRmFpbHVyZSBSZWNlaXZlZCBpbiAiRmVlZGJhY2sgTWFuYWdlciIgKDxpbnAyOmZvcm1zdWJzLi1pdGVtX0ZpZWxkIG5hbWU9IkZvcm1TdWJtaXNzaW9uSWQiLz4pCgpOZXcgRW1haWwgRGVsaXZlcnkgRmFpbHVyZSBSZWNlaXZlZCBpbiAmcXVvdDtGZWVkYmFjayBNYW5hZ2VyJnF1b3Q7LjxiciAvPg0KPGJyIC8+DQpPcmlnaW5hbCBGZWVkYmFja0lkOiA8aW5wMjpmb3Jtc3Vicy4taXRlbV9GaWVsZCBuYW1lPSJGb3JtU3VibWlzc2lvbklkIi8+IDxiciAvPg0KT3JpZ2luYWwgU3ViamVjdDogPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRm9ybUZpZWxkIHJvbGU9InN1YmplY3QiLz4gPGJyIC8+DQo8YnIgLz4NClBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIGluIG9yZGVyIHRvIHJldmlldyBhbmQgcmVwbHkgdG8gdGhlIHVzZXIu - U3ViamVjdDogPGlucDI6bV9QYXJhbSBuYW1lPSJzdWJqZWN0Ii8+ICN2ZXJpZnk8aW5wMjpzdWJtaXNzaW9uLWxvZ19GaWVsZCBuYW1lPSJWZXJpZnlDb2RlIi8+Cgo8aW5wMjptX1BhcmFtIG5hbWU9Im1lc3NhZ2UiLz4= - U3ViamVjdDogVGhhbmsgWW91IGZvciBDb250YWN0aW5nIFVzIQoKPHA+VGhhbmsgeW91IGZvciBjb250YWN0aW5nIHVzLiBXZSdsbCBiZSBpbiB0b3VjaCB3aXRoIHlvdSBzaG9ydGx5ITwvcD4= - U3ViamVjdDogTmV3IGZvcm0gc3VibWlzc2lvbgoKPHA+Rm9ybSBoYXMgYmVlbiBzdWJtaXR0ZWQuIFBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIHRvIHJldmlldyB0aGUgc3VibWlzc2lvbiE8L3A+ - U3ViamVjdDogUm9vdCBSZXNldCBQYXNzd29yZAoKWW91ciBuZXcgcGFzc3dvcmQgaXM6IDxpbnAyOm1fUGFyYW0gbmFtZT0icGFzc3dvcmQiLz4= - U3ViamVjdDogSW4tcG9ydGFsIHJlZ2lzdHJhdGlvbgoKRGVhciA8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIgLz4gPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSJMYXN0TmFtZSIgLz4sDQoNClRoYW5rIHlvdSBmb3IgcmVnaXN0ZXJpbmcgb24gPGlucDI6bV9CYXNlVXJsLz4uIFlvdXIgcmVnaXN0cmF0aW9uIGlzIG5vdyBhY3RpdmUuDQo8aW5wMjptX2lmIGNoZWNrPSJ1LnJlZ2lzdGVyX0ZpZWxkIiBuYW1lPSJFbWFpbCI+DQo8YnIvPjxici8+DQpQbGVhc2UgY2xpY2sgaGVyZSB0byB2ZXJpZnkgeW91ciBFLW1haWwgYWRkcmVzczoNCjxhIGhyZWY9IjxpbnAyOnUucmVnaXN0ZXJfQ29uZmlybVBhc3N3b3JkTGluayB0PSJwbGF0Zm9ybS9teV9hY2NvdW50L3ZlcmlmeV9lbWFpbCIgbm9fYW1wPSIxIi8+Ij48aW5wMjp1LnJlZ2lzdGVyX0NvbmZpcm1QYXNzd29yZExpbmsgdD0icGxhdGZvcm0vbXlfYWNjb3VudC92ZXJpZnlfZW1haWwiIG5vX2FtcD0iMSIvPjwvYT48YnIvPjxici8+DQo8L2lucDI6bV9pZj4= - U3ViamVjdDogTmV3IFVzZXIgUmVnaXN0cmF0aW9uICg8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+KQoKQSBuZXcgdXNlciAiPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSdVc2VybmFtZScvPiIgaGFzIGJlZW4gYWRkZWQu - U3ViamVjdDogTmV3IHVzZXIgaGFzIGJlZW4gY3JlYXRlZAoKRGVhciA8aW5wMjp1X0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIvPiwNCg0KQSBuZXcgdXNlciBoYXMgYmVlbiBjcmVhdGVkIGFuZCBhc3NpZ25lZCB0byB5b3UNCg0KTm93IHlvdSBjYW4gbG9naW4gdXNpbmcgdGhlIGZvbGxvd2luZyBjcmVkZW50aWFsczoNCg0KPGlucDI6bV9pZiBjaGVjaz0idV9GaWVsZCIgbmFtZT0iVXNlcm5hbWUiPlVzZXJuYW1lOiA8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+PGlucDI6bV9lbHNlLz5FLW1haWw6IDxpbnAyOnVfRmllbGQgbmFtZT0iRW1haWwiLz48L2lucDI6bV9pZj4gDQpQYXNzd29yZDogPGlucDI6dV9GaWVsZCBuYW1lPSJQYXNzd29yZF9wbGFpbiIvPiANCg== - U3ViamVjdDogTmV3IFVzZXIgUmVnaXN0cmF0aW9uICg8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+PGlucDI6bV9pZiBjaGVjaz0ibV9HZXRDb25maWciIG5hbWU9IlVzZXJfQWxsb3dfTmV3IiBlcXVhbHNfdG89IjQiPiAtIEFjdGl2YXRpb24gRW1haWw8L2lucDI6bV9pZj4pCgpEZWFyIDxpbnAyOnUucmVnaXN0ZXJfRmllbGQgbmFtZT0iRmlyc3ROYW1lIiAvPiA8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9Ikxhc3ROYW1lIiAvPiw8YnIgLz4NCjxiciAvPg0KPGlucDI6bV9pZiBjaGVjaz0ibV9HZXRDb25maWciIG5hbWU9IlVzZXJfQWxsb3dfTmV3IiBlcXVhbHNfdG89IjQiPg0KCVRoYW5rIHlvdSBmb3IgcmVnaXN0ZXJpbmcgb24gPGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPiB3ZWJzaXRlLiBUbyBhY3RpdmF0ZSB5b3VyIHJlZ2lzdHJhdGlvbiBwbGVhc2UgZm9sbG93IGxpbmsgYmVsb3cuIDxpbnAyOnUucmVnaXN0ZXJfQWN0aXZhdGlvbkxpbmsgdGVtcGxhdGU9InBsYXRmb3JtL2xvZ2luL2FjdGl2YXRlX2NvbmZpcm0iLz4NCjxpbnAyOm1fZWxzZS8+DQoJVGhhbmsgeW91IGZvciByZWdpc3RlcmluZyBvbiA8aW5wMjptX0xpbmsgdGVtcGxhdGU9ImluZGV4Ii8+IHdlYnNpdGUuIFlvdXIgcmVnaXN0cmF0aW9uIHdpbGwgYmUgYWN0aXZlIGFmdGVyIGFwcHJvdmFsLiANCgkNCgk8aW5wMjptX2lmIGNoZWNrPSJ1LnJlZ2lzdGVyX0ZpZWxkIiBuYW1lPSJFbWFpbCI+DQoJCTxici8+PGJyLz4NCgkJUGxlYXNlIGNsaWNrIGhlcmUgdG8gdmVyaWZ5IHlvdXIgRS1tYWlsIGFkZHJlc3M6DQoJCTxhIGhyZWY9IjxpbnAyOnUucmVnaXN0ZXJfQ29uZmlybVBhc3N3b3JkTGluayB0PSJwbGF0Zm9ybS9teV9hY2NvdW50L3ZlcmlmeV9lbWFpbCIgbm9fYW1wPSIxIi8+Ij48aW5wMjp1LnJlZ2lzdGVyX0NvbmZpcm1QYXNzd29yZExpbmsgdD0icGxhdGZvcm0vbXlfYWNjb3VudC92ZXJpZnlfZW1haWwiIG5vX2FtcD0iMSIvPjwvYT48YnIvPjxici8+DQoJPC9pbnAyOm1faWY+DQo8L2lucDI6bV9pZj4= - U3ViamVjdDogTmV3IFVzZXIgUmVnaXN0ZXJlZAoKQSBuZXcgdXNlciAiPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgaGFzIHJlZ2lzdGVyZWQgYW5kIGlzIHBlbmRpbmcgYWRtaW5pc3RyYXRpdmUgYXBwcm92YWwu - U3ViamVjdDogWW91ciBBY2NvdW50IGlzIEFjdGl2ZQoKV2VsY29tZSB0byA8aW5wMjptX0Jhc2VVcmwvPiENCg0KWW91ciB1c2VyIHJlZ2lzdHJhdGlvbiBoYXMgYmVlbiBhcHByb3ZlZC4gWW91ciB1c2VyIG5hbWUgaXM6ICI8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+Ii4= - U3ViamVjdDogTmV3IFVzZXIgQWNjb3VudCAiPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgd2FzIEFwcHJvdmVkCgpVc2VyICI8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+IiBoYXMgYmVlbiBhcHByb3ZlZC4= - U3ViamVjdDogWW91ciBSZWdpc3RyYXRpb24gaGFzIGJlZW4gRGVuaWVkCgpZb3VyIHJlZ2lzdHJhdGlvbiBvbiA8YSBocmVmPSI8aW5wMjptX0Jhc2VVcmwvPiI+PGlucDI6bV9CYXNlVXJsLz48L2E+IHdlYnNpdGUgaGFzIGJlZW4gZGVuaWVkLg== - U3ViamVjdDogVXNlciBSZWdpc3RyYXRpb24gZm9yICAiPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgaGFzIGJlZW4gRGVuaWVkCgpVc2VyICI8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+IiBoYXMgYmVlbiBkZW5pZWQu - U3ViamVjdDogQ2hhbmdlZCBFLW1haWwgUm9sbGJhY2sKCkhlbGxvLDxici8+PGJyLz4NCg0KSXQgc2VlbXMgdGhhdCB5b3UgaGF2ZSBjaGFuZ2VkIGUtbWFpbCBpbiB5b3VyIEluLXBvcnRhbCBhY2NvdW50LiBZb3UgbWF5IHVuZG8gdGhpcyBjaGFuZ2UgYnkgY2xpY2tpbmcgb24gdGhlIGxpbmsgYmVsb3c6PGJyLz48YnIvPg0KDQo8YSBocmVmPSI8aW5wMjp1X1VuZG9FbWFpbENoYW5nZUxpbmsgdGVtcGxhdGU9InBsYXRmb3JtL215X2FjY291bnQvcmVzdG9yZV9lbWFpbCIvPiI+PGlucDI6dV9VbmRvRW1haWxDaGFuZ2VMaW5rIHRlbXBsYXRlPSJwbGF0Zm9ybS9teV9hY2NvdW50L3Jlc3RvcmVfZW1haWwiLz48L2E+PGJyLz48YnIvPg0KDQpJZiB5b3UgYmVsaWV2ZSB5b3UgaGF2ZSByZWNlaXZlZCB0aGlzIGVtYWlsIGluIGVycm9yLCBwbGVhc2UgaWdub3JlIHRoaXMgZW1haWwuIFlvdXIgYWNjb3VudCB3aWxsIGJlIGxpbmtlZCB0byBhbm90aGVyIGUtbWFpbCB1bmxlc3MgeW91IGhhdmUgY2xpY2tlZCBvbiB0aGUgYWJvdmUgbGluay4= - U3ViamVjdDogQ2hhbmdlZCBFLW1haWwgVmVyaWZpY2F0aW9uCgpIZWxsbyw8YnIvPjxici8+DQoNCkl0IHNlZW1zIHRoYXQgeW91IGhhdmUgY2hhbmdlZCBlLW1haWwgaW4geW91ciBJbi1wb3J0YWwgYWNjb3VudC4gUGxlYXNlIHZlcmlmeSB0aGlzIG5ldyBlLW1haWwgYnkgY2xpY2tpbmcgb24gdGhlIGxpbmsgYmVsb3c6PGJyLz48YnIvPg0KDQo8YSBocmVmPSI8aW5wMjp1X0NvbmZpcm1QYXNzd29yZExpbmsgdD0icGxhdGZvcm0vbXlfYWNjb3VudC92ZXJpZnlfZW1haWwiIG5vX2FtcD0iMSIvPiI+PGlucDI6dV9Db25maXJtUGFzc3dvcmRMaW5rIHQ9InBsYXRmb3JtL215X2FjY291bnQvdmVyaWZ5X2VtYWlsIiBub19hbXA9IjEiLz48L2E+PGJyLz48YnIvPg0KDQpJZiB5b3UgYmVsaWV2ZSB5b3UgaGF2ZSByZWNlaXZlZCB0aGlzIGVtYWlsIGluIGVycm9yLCBwbGVhc2UgaWdub3JlIHRoaXMgZW1haWwuIFlvdXIgZW1haWwgd2lsbCBub3QgZ2V0IHZlcmlmaWVkIHN0YXR1cyB1bmxlc3MgeW91IGhhdmUgY2xpY2tlZCBvbiB0aGUgYWJvdmUgbGluay4NCg== - U3ViamVjdDogTWVtYmVyc2hpcCBFeHBpcmF0aW9uIE5vdGljZQoKWW91ciBtZW1iZXJzaGlwIG9uIDxpbnAyOm1fQmFzZVVybC8+IHdlYnNpdGUgd2lsbCBzb29uIGV4cGlyZS4= - U3ViamVjdDogTWVtYmVyc2hpcCBFeHBpcmF0aW9uIE5vdGljZSBmb3IgIjxpbnAyOnVfRmllbGQgbmFtZT0iVXNlcm5hbWUiLz4iIFNlbnQKClVzZXIgPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiBtZW1iZXJzaGlwIHdpbGwgZXhwaXJlIHNvb24u - U3ViamVjdDogWW91ciBNZW1iZXJzaGlwIEV4cGlyZWQKCllvdXIgbWVtYmVyc2hpcCBvbiA8aW5wMjptX0Jhc2VVcmwvPiB3ZWJzaXRlIGhhcyBleHBpcmVkLg== - U3ViamVjdDogVXNlcidzIE1lbWJlcnNoaXAgRXhwaXJlZCAgKCA8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+KQoKVXNlcidzICg8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+KSBtZW1iZXJzaGlwIG9uIDxpbnAyOm1fQmFzZVVybC8+IHdlYnNpdGUgaGFzIGV4cGlyZWQu - U3ViamVjdDogTmV3IHBhc3N3b3JkIGdlbmVyYXRlZAoKRGVhciA8aW5wMjp1X0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIvPiwNCg0KQSBuZXcgcGFzc3dvcmQgaGFzIGJlZW4gZ2VuZXJhdGVkIGZvciB5b3VyIHVzZXIuDQoNCk5vdyB5b3UgY2FuIGxvZ2luIHVzaW5nIHRoZSBmb2xsb3dpbmcgY3JlZGVudGlhbHM6DQoNCjxpbnAyOm1faWYgY2hlY2s9InVfRmllbGQiIG5hbWU9IlVzZXJuYW1lIj5Vc2VybmFtZTogPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPjxpbnAyOm1fZWxzZS8+RS1tYWlsOiA8aW5wMjp1X0ZpZWxkIG5hbWU9IkVtYWlsIi8+PC9pbnAyOm1faWY+IA0KUGFzc3dvcmQ6IDxpbnAyOnVfRmllbGQgbmFtZT0iUGFzc3dvcmRfcGxhaW4iLz4g - U3ViamVjdDogUmVzZXQgUGFzc3dvcmQgQ29uZmlybWF0aW9uCgpIZWxsbyw8YnIvPjxici8+DQoNCkl0IHNlZW1zIHRoYXQgeW91IGhhdmUgcmVxdWVzdGVkIGEgcGFzc3dvcmQgcmVzZXQgZm9yIHlvdXIgSW4tcG9ydGFsIGFjY291bnQuIElmIHlvdSB3b3VsZCBsaWtlIHRvIHByb2NlZWQgYW5kIGNoYW5nZSB0aGUgcGFzc3dvcmQsIHBsZWFzZSBjbGljayBvbiB0aGUgbGluayBiZWxvdzo8YnIvPjxici8+DQoNCjxhIGhyZWY9IjxpbnAyOnVfQ29uZmlybVBhc3N3b3JkTGluayBub19hbXA9IjEiLz4iPjxpbnAyOnVfQ29uZmlybVBhc3N3b3JkTGluayBub19hbXA9IjEiLz48L2E+PGJyLz48YnIvPg0KDQpZb3Ugd2lsbCByZWNlaXZlIGEgc2Vjb25kIGVtYWlsIHdpdGggeW91ciBuZXcgcGFzc3dvcmQgc2hvcnRseS48YnIvPjxici8+DQoNCklmIHlvdSBiZWxpZXZlIHlvdSBoYXZlIHJlY2VpdmVkIHRoaXMgZW1haWwgaW4gZXJyb3IsIHBsZWFzZSBpZ25vcmUgdGhpcyBlbWFpbC4gWW91ciBwYXNzd29yZCB3aWxsIG5vdCBiZSBjaGFuZ2VkIHVubGVzcyB5b3UgaGF2ZSBjbGlja2VkIG9uIHRoZSBhYm92ZSBsaW5rLg0K - U3ViamVjdDogU3Vic2NyaWJlZCB0byBhIE1haWxpbmcgTGlzdCBvbiA8aW5wMjptX0Jhc2VVcmwvPgoKWW91IGhhdmUgc3Vic2NyaWJlZCB0byBhIG1haWxpbmcgbGlzdCBvbiA8aW5wMjptX0Jhc2VVcmwvPiB3ZWJzaXRlLg== - U3ViamVjdDogTmV3IFVzZXIgaGFzIFN1YnNjcmliZWQgdG8gYSBNYWxsaW5nIExpc3QKCk5ldyB1c2VyIDxpbnAyOnVfRmllbGQgbmFtZT0iRW1haWwiLz4gaGFzIHN1YnNjcmliZWQgdG8gYSBtYWlsaW5nIGxpc3Qgb24gPGEgaHJlZj0iPGlucDI6bV9CYXNlVXJsLz4iPjxpbnAyOm1fQmFzZVVybC8+PC9hPiB3ZWJzaXRlLg== - U3ViamVjdDogQ2hlY2sgb3V0IHRoaXMgV2Vic2l0ZQoKSGVsbG8sPC9icj48L2JyPg0KDQpUaGlzIG1lc3NhZ2UgaGFzIGJlZW4gc2VudCB0byB5b3UgZnJvbSBvbmUgb2YgeW91ciBmcmllbmRzLjwvYnI+PC9icj4NCkNoZWNrIG91dCB0aGlzIHNpdGU6IDxhIGhyZWY9IjxpbnAyOm1fQmFzZVVybC8+Ij48aW5wMjptX0Jhc2VVcmwvPjwvYT4h - U3ViamVjdDogV2Vic2l0ZSBTdWdnZXN0ZWQgdG8gYSBGcmllbmQKCkEgdmlzaXRvciBzdWdnZXN0ZWQgPGEgaHJlZj0iPGlucDI6bV9CYXNlVXJsLz4iPjxpbnAyOm1fQmFzZVVybC8+PC9hPiB3ZWJzaXRlIHRvIGEgZnJpZW5kLg== - U3ViamVjdDogWW91IGhhdmUgYmVlbiB1bnN1YnNjcmliZWQKCllvdSBoYXZlIHN1Y2Nlc3NmdWxseSB1bnN1YnNjcmliZWQgZnJvbSB0aGUgbWFpbGluZyBsaXN0IG9uIDxhIGhyZWY9IjxpbnAyOm1fQmFzZVVybCAvPiI+PGlucDI6bV9CYXNlVXJsIC8+PC9hPiB3ZWJzaXRlLg== - U3ViamVjdDogVXNlciBVbnN1YnNyaWJlZCBmcm9tIE1haWxpbmcgTGlzdAoKQSB1c2VyICI8aW5wMjp1X0ZpZWxkIG5hbWU9IkVtYWlsIi8+IiBoYXMgdW5zdWJzY3JpYmVkIGZyb20gdGhlIG1haWxpbmcgbGlzdCBvbiA8YSBocmVmPSI8aW5wMjptX0Jhc2VVcmwvPiI+PGlucDI6bV9CYXNlVXJsLz48L2E+Lg== - U3ViamVjdDogVXNlciBSZWdpc3RyYXRpb24gaXMgVmFsaWRhdGVkCgpXZWxjb21lIHRvIEluLXBvcnRhbCE8YnIvPjxici8+DQoNCllvdXIgdXNlciByZWdpc3RyYXRpb24gaGFzIGJlZW4gYXBwcm92ZWQuIFlvdSBjYW4gbG9naW4gbm93IDxhIGhyZWY9IjxpbnAyOm1fQmFzZVVybC8+Ij48aW5wMjptX0Jhc2VVcmwvPjwvYT4gdXNpbmcgdGhlIGZvbGxvd2luZyBpbmZvcm1hdGlvbjo8YnIvPjxici8+DQoNCj09PT09PT09PT09PT09PT09PTxici8+DQpVc2VybmFtZTogIjxpbnAyOnVfRmllbGQgbmFtZT0iVXNlcm5hbWUiLz4iPGJyLz4NClBhc3N3b3JkOiAiPGlucDI6dV9GaWVsZCBuYW1lPSJQYXNzd29yZF9wbGFpbiIvPiI8YnIvPg0KPT09PT09PT09PT09PT09PT09PGJyLz48YnIvPg0K - U3ViamVjdDogTmV3IFVzZXIgUmVnaXN0cmF0aW9uIGlzIFZhbGlkYXRlZAoKVXNlciAiPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgaGFzIGJlZW4gdmFsaWRhdGVkLg== + + TmV3IENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIC0gQWRkZWQ= + WW91ciBzdWdnZXN0ZWQgY2F0ZWdvcnkgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaGFzIGJlZW4gYWRkZWQu + + + TmV3IENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIFN1Ym1pdHRlZCBieSBVc2Vycw== + QSBjYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBhZGRlZC4= + + + U3VnZ2VzdGVkIENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGlzIFBlbmRpbmc= + VGhlIGNhdGVnb3J5IHlvdSBzdWdnZXN0ZWQgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaXMgcGVuZGluZyBmb3IgYWRtaW5pc3RyYXRpdmUgYXBwcm92YWwuDQoNClRoYW5rIHlvdSE= + + + U3VnZ2VzdGVkIENhdGVnb3J5ICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGlzIFBlbmRpbmc= + QSBjYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBhZGRlZCwgcGVuZGluZyB5b3VyIGNvbmZpcm1hdGlvbi4gIFBsZWFzZSByZXZpZXcgdGhlIGNhdGVnb3J5IGFuZCBhcHByb3ZlIG9yIGRlbnkgaXQu + + + QSBjYXRlZ29yeSBoYXMgYmVlbiBhcHByb3ZlZA== + WW91ciBzdWdnZXN0ZWQgY2F0ZWdvcnkgIjxpbnAyOmNfRmllbGQgbmFtZT0iTmFtZSIvPiIgaGFzIGJlZW4gYXBwcm92ZWQu + + + WW91ciBDYXRlZ29yeSAiPGlucDI6Y19GaWVsZCBuYW1lPSJOYW1lIi8+IiBoYXMgYmVlbiBEZW5pZWQ= + WW91ciBjYXRlZ29yeSBzdWdnZXN0aW9uICI8aW5wMjpjX0ZpZWxkIG5hbWU9Ik5hbWUiLz4iIGhhcyBiZWVuIGRlbmllZC4= + + + Q29tbW9uIEZvb3RlciBUZW1wbGF0ZQ== + PGJyLz48YnIvPg0KDQpTaW5jZXJlbHksPGJyLz48YnIvPg0KDQpXZWJzaXRlIGFkbWluaXN0cmF0aW9uLg== + + + TmV3IEVtYWlsIFJFUExZIFJlY2VpdmVkIGluICJGZWVkYmFjayBNYW5hZ2VyIiAoPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRmllbGQgbmFtZT0iRm9ybVN1Ym1pc3Npb25JZCIvPik= + TmV3IEVtYWlsIFJFUExZIFJlY2VpdmVkIGluICZxdW90O0ZlZWRiYWNrIE1hbmFnZXImcXVvdDsuPGJyIC8+DQo8YnIgLz4NCk9yaWdpbmFsIEZlZWRiYWNrSWQ6IDxpbnAyOmZvcm1zdWJzLi1pdGVtX0ZpZWxkIG5hbWU9IkZvcm1TdWJtaXNzaW9uSWQiLz4gPGJyIC8+DQpPcmlnaW5hbCBTdWJqZWN0OiA8aW5wMjpmb3Jtc3Vicy4taXRlbV9Gb3JtRmllbGQgcm9sZT0ic3ViamVjdCIvPiA8YnIgLz4NCjxiciAvPg0KUGxlYXNlIHByb2NlZWQgdG8gdGhlIEFkbWluIENvbnNvbGUgaW4gb3JkZXIgdG8gcmV2aWV3IGFuZCByZXBseSB0byB0aGUgdXNlci4= + + + TmV3IEVtYWlsIC0gRGVsaXZlcnkgRmFpbHVyZSBSZWNlaXZlZCBpbiAiRmVlZGJhY2sgTWFuYWdlciIgKDxpbnAyOmZvcm1zdWJzLi1pdGVtX0ZpZWxkIG5hbWU9IkZvcm1TdWJtaXNzaW9uSWQiLz4p + TmV3IEVtYWlsIERlbGl2ZXJ5IEZhaWx1cmUgUmVjZWl2ZWQgaW4gJnF1b3Q7RmVlZGJhY2sgTWFuYWdlciZxdW90Oy48YnIgLz4NCjxiciAvPg0KT3JpZ2luYWwgRmVlZGJhY2tJZDogPGlucDI6Zm9ybXN1YnMuLWl0ZW1fRmllbGQgbmFtZT0iRm9ybVN1Ym1pc3Npb25JZCIvPiA8YnIgLz4NCk9yaWdpbmFsIFN1YmplY3Q6IDxpbnAyOmZvcm1zdWJzLi1pdGVtX0Zvcm1GaWVsZCByb2xlPSJzdWJqZWN0Ii8+IDxiciAvPg0KPGJyIC8+DQpQbGVhc2UgcHJvY2VlZCB0byB0aGUgQWRtaW4gQ29uc29sZSBpbiBvcmRlciB0byByZXZpZXcgYW5kIHJlcGx5IHRvIHRoZSB1c2VyLg== + + + PGlucDI6bV9QYXJhbSBuYW1lPSJzdWJqZWN0Ii8+ICN2ZXJpZnk8aW5wMjpzdWJtaXNzaW9uLWxvZ19GaWVsZCBuYW1lPSJWZXJpZnlDb2RlIi8+ + PGlucDI6bV9QYXJhbSBuYW1lPSJtZXNzYWdlIi8+ + + + VGhhbmsgWW91IGZvciBDb250YWN0aW5nIFVzIQ== + PHA+VGhhbmsgeW91IGZvciBjb250YWN0aW5nIHVzLiBXZSdsbCBiZSBpbiB0b3VjaCB3aXRoIHlvdSBzaG9ydGx5ITwvcD4= + + + TmV3IGZvcm0gc3VibWlzc2lvbg== + PHA+Rm9ybSBoYXMgYmVlbiBzdWJtaXR0ZWQuIFBsZWFzZSBwcm9jZWVkIHRvIHRoZSBBZG1pbiBDb25zb2xlIHRvIHJldmlldyB0aGUgc3VibWlzc2lvbiE8L3A+ + + + Um9vdCBSZXNldCBQYXNzd29yZA== + WW91ciBuZXcgcGFzc3dvcmQgaXM6IDxpbnAyOm1fUGFyYW0gbmFtZT0icGFzc3dvcmQiLz4= + + + SW4tcG9ydGFsIHJlZ2lzdHJhdGlvbg== + RGVhciA8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIgLz4gPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSJMYXN0TmFtZSIgLz4sDQoNClRoYW5rIHlvdSBmb3IgcmVnaXN0ZXJpbmcgb24gPGlucDI6bV9CYXNlVXJsLz4uIFlvdXIgcmVnaXN0cmF0aW9uIGlzIG5vdyBhY3RpdmUuDQo8aW5wMjptX2lmIGNoZWNrPSJ1LnJlZ2lzdGVyX0ZpZWxkIiBuYW1lPSJFbWFpbCI+DQo8YnIvPjxici8+DQpQbGVhc2UgY2xpY2sgaGVyZSB0byB2ZXJpZnkgeW91ciBFLW1haWwgYWRkcmVzczoNCjxhIGhyZWY9IjxpbnAyOnUucmVnaXN0ZXJfQ29uZmlybVBhc3N3b3JkTGluayB0PSJwbGF0Zm9ybS9teV9hY2NvdW50L3ZlcmlmeV9lbWFpbCIgbm9fYW1wPSIxIi8+Ij48aW5wMjp1LnJlZ2lzdGVyX0NvbmZpcm1QYXNzd29yZExpbmsgdD0icGxhdGZvcm0vbXlfYWNjb3VudC92ZXJpZnlfZW1haWwiIG5vX2FtcD0iMSIvPjwvYT48YnIvPjxici8+DQo8L2lucDI6bV9pZj4= + + + TmV3IFVzZXIgUmVnaXN0cmF0aW9uICg8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+KQ== + QSBuZXcgdXNlciAiPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSdVc2VybmFtZScvPiIgaGFzIGJlZW4gYWRkZWQu + + + TmV3IHVzZXIgaGFzIGJlZW4gY3JlYXRlZA== + RGVhciA8aW5wMjp1X0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIvPiwNCg0KQSBuZXcgdXNlciBoYXMgYmVlbiBjcmVhdGVkIGFuZCBhc3NpZ25lZCB0byB5b3UNCg0KTm93IHlvdSBjYW4gbG9naW4gdXNpbmcgdGhlIGZvbGxvd2luZyBjcmVkZW50aWFsczoNCg0KPGlucDI6bV9pZiBjaGVjaz0idV9GaWVsZCIgbmFtZT0iVXNlcm5hbWUiPlVzZXJuYW1lOiA8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+PGlucDI6bV9lbHNlLz5FLW1haWw6IDxpbnAyOnVfRmllbGQgbmFtZT0iRW1haWwiLz48L2lucDI6bV9pZj4gDQpQYXNzd29yZDogPGlucDI6dV9GaWVsZCBuYW1lPSJQYXNzd29yZF9wbGFpbiIvPiANCg== + + + TmV3IFVzZXIgUmVnaXN0cmF0aW9uICg8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+PGlucDI6bV9pZiBjaGVjaz0ibV9HZXRDb25maWciIG5hbWU9IlVzZXJfQWxsb3dfTmV3IiBlcXVhbHNfdG89IjQiPiAtIEFjdGl2YXRpb24gRW1haWw8L2lucDI6bV9pZj4p + RGVhciA8aW5wMjp1LnJlZ2lzdGVyX0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIgLz4gPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSJMYXN0TmFtZSIgLz4sPGJyIC8+DQo8YnIgLz4NCjxpbnAyOm1faWYgY2hlY2s9Im1fR2V0Q29uZmlnIiBuYW1lPSJVc2VyX0FsbG93X05ldyIgZXF1YWxzX3RvPSI0Ij4NCglUaGFuayB5b3UgZm9yIHJlZ2lzdGVyaW5nIG9uIDxpbnAyOm1fTGluayB0ZW1wbGF0ZT0iaW5kZXgiLz4gd2Vic2l0ZS4gVG8gYWN0aXZhdGUgeW91ciByZWdpc3RyYXRpb24gcGxlYXNlIGZvbGxvdyBsaW5rIGJlbG93LiA8aW5wMjp1LnJlZ2lzdGVyX0FjdGl2YXRpb25MaW5rIHRlbXBsYXRlPSJwbGF0Zm9ybS9sb2dpbi9hY3RpdmF0ZV9jb25maXJtIi8+DQo8aW5wMjptX2Vsc2UvPg0KCVRoYW5rIHlvdSBmb3IgcmVnaXN0ZXJpbmcgb24gPGlucDI6bV9MaW5rIHRlbXBsYXRlPSJpbmRleCIvPiB3ZWJzaXRlLiBZb3VyIHJlZ2lzdHJhdGlvbiB3aWxsIGJlIGFjdGl2ZSBhZnRlciBhcHByb3ZhbC4gDQoJDQoJPGlucDI6bV9pZiBjaGVjaz0idS5yZWdpc3Rlcl9GaWVsZCIgbmFtZT0iRW1haWwiPg0KCQk8YnIvPjxici8+DQoJCVBsZWFzZSBjbGljayBoZXJlIHRvIHZlcmlmeSB5b3VyIEUtbWFpbCBhZGRyZXNzOg0KCQk8YSBocmVmPSI8aW5wMjp1LnJlZ2lzdGVyX0NvbmZpcm1QYXNzd29yZExpbmsgdD0icGxhdGZvcm0vbXlfYWNjb3VudC92ZXJpZnlfZW1haWwiIG5vX2FtcD0iMSIvPiI+PGlucDI6dS5yZWdpc3Rlcl9Db25maXJtUGFzc3dvcmRMaW5rIHQ9InBsYXRmb3JtL215X2FjY291bnQvdmVyaWZ5X2VtYWlsIiBub19hbXA9IjEiLz48L2E+PGJyLz48YnIvPg0KCTwvaW5wMjptX2lmPg0KPC9pbnAyOm1faWY+ + + + TmV3IFVzZXIgUmVnaXN0ZXJlZA== + QSBuZXcgdXNlciAiPGlucDI6dS5yZWdpc3Rlcl9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgaGFzIHJlZ2lzdGVyZWQgYW5kIGlzIHBlbmRpbmcgYWRtaW5pc3RyYXRpdmUgYXBwcm92YWwu + + + WW91ciBBY2NvdW50IGlzIEFjdGl2ZQ== + V2VsY29tZSB0byA8aW5wMjptX0Jhc2VVcmwvPiENCg0KWW91ciB1c2VyIHJlZ2lzdHJhdGlvbiBoYXMgYmVlbiBhcHByb3ZlZC4gWW91ciB1c2VyIG5hbWUgaXM6ICI8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+Ii4= + + + TmV3IFVzZXIgQWNjb3VudCAiPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgd2FzIEFwcHJvdmVk + VXNlciAiPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgaGFzIGJlZW4gYXBwcm92ZWQu + + + WW91ciBSZWdpc3RyYXRpb24gaGFzIGJlZW4gRGVuaWVk + WW91ciByZWdpc3RyYXRpb24gb24gPGEgaHJlZj0iPGlucDI6bV9CYXNlVXJsLz4iPjxpbnAyOm1fQmFzZVVybC8+PC9hPiB3ZWJzaXRlIGhhcyBiZWVuIGRlbmllZC4= + + + VXNlciBSZWdpc3RyYXRpb24gZm9yICAiPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgaGFzIGJlZW4gRGVuaWVk + VXNlciAiPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgaGFzIGJlZW4gZGVuaWVkLg== + + + Q2hhbmdlZCBFLW1haWwgUm9sbGJhY2s= + SGVsbG8sPGJyLz48YnIvPg0KDQpJdCBzZWVtcyB0aGF0IHlvdSBoYXZlIGNoYW5nZWQgZS1tYWlsIGluIHlvdXIgSW4tcG9ydGFsIGFjY291bnQuIFlvdSBtYXkgdW5kbyB0aGlzIGNoYW5nZSBieSBjbGlja2luZyBvbiB0aGUgbGluayBiZWxvdzo8YnIvPjxici8+DQoNCjxhIGhyZWY9IjxpbnAyOnVfVW5kb0VtYWlsQ2hhbmdlTGluayB0ZW1wbGF0ZT0icGxhdGZvcm0vbXlfYWNjb3VudC9yZXN0b3JlX2VtYWlsIi8+Ij48aW5wMjp1X1VuZG9FbWFpbENoYW5nZUxpbmsgdGVtcGxhdGU9InBsYXRmb3JtL215X2FjY291bnQvcmVzdG9yZV9lbWFpbCIvPjwvYT48YnIvPjxici8+DQoNCklmIHlvdSBiZWxpZXZlIHlvdSBoYXZlIHJlY2VpdmVkIHRoaXMgZW1haWwgaW4gZXJyb3IsIHBsZWFzZSBpZ25vcmUgdGhpcyBlbWFpbC4gWW91ciBhY2NvdW50IHdpbGwgYmUgbGlua2VkIHRvIGFub3RoZXIgZS1tYWlsIHVubGVzcyB5b3UgaGF2ZSBjbGlja2VkIG9uIHRoZSBhYm92ZSBsaW5rLg== + + + Q2hhbmdlZCBFLW1haWwgVmVyaWZpY2F0aW9u + SGVsbG8sPGJyLz48YnIvPg0KDQpJdCBzZWVtcyB0aGF0IHlvdSBoYXZlIGNoYW5nZWQgZS1tYWlsIGluIHlvdXIgSW4tcG9ydGFsIGFjY291bnQuIFBsZWFzZSB2ZXJpZnkgdGhpcyBuZXcgZS1tYWlsIGJ5IGNsaWNraW5nIG9uIHRoZSBsaW5rIGJlbG93Ojxici8+PGJyLz4NCg0KPGEgaHJlZj0iPGlucDI6dV9Db25maXJtUGFzc3dvcmRMaW5rIHQ9InBsYXRmb3JtL215X2FjY291bnQvdmVyaWZ5X2VtYWlsIiBub19hbXA9IjEiLz4iPjxpbnAyOnVfQ29uZmlybVBhc3N3b3JkTGluayB0PSJwbGF0Zm9ybS9teV9hY2NvdW50L3ZlcmlmeV9lbWFpbCIgbm9fYW1wPSIxIi8+PC9hPjxici8+PGJyLz4NCg0KSWYgeW91IGJlbGlldmUgeW91IGhhdmUgcmVjZWl2ZWQgdGhpcyBlbWFpbCBpbiBlcnJvciwgcGxlYXNlIGlnbm9yZSB0aGlzIGVtYWlsLiBZb3VyIGVtYWlsIHdpbGwgbm90IGdldCB2ZXJpZmllZCBzdGF0dXMgdW5sZXNzIHlvdSBoYXZlIGNsaWNrZWQgb24gdGhlIGFib3ZlIGxpbmsuDQo= + + + TWVtYmVyc2hpcCBFeHBpcmF0aW9uIE5vdGljZQ== + WW91ciBtZW1iZXJzaGlwIG9uIDxpbnAyOm1fQmFzZVVybC8+IHdlYnNpdGUgd2lsbCBzb29uIGV4cGlyZS4= + + + TWVtYmVyc2hpcCBFeHBpcmF0aW9uIE5vdGljZSBmb3IgIjxpbnAyOnVfRmllbGQgbmFtZT0iVXNlcm5hbWUiLz4iIFNlbnQ= + VXNlciA8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+IG1lbWJlcnNoaXAgd2lsbCBleHBpcmUgc29vbi4= + + + WW91ciBNZW1iZXJzaGlwIEV4cGlyZWQ= + WW91ciBtZW1iZXJzaGlwIG9uIDxpbnAyOm1fQmFzZVVybC8+IHdlYnNpdGUgaGFzIGV4cGlyZWQu + + + VXNlcidzIE1lbWJlcnNoaXAgRXhwaXJlZCAgKCA8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+KQ== + VXNlcidzICg8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+KSBtZW1iZXJzaGlwIG9uIDxpbnAyOm1fQmFzZVVybC8+IHdlYnNpdGUgaGFzIGV4cGlyZWQu + + + TmV3IHBhc3N3b3JkIGdlbmVyYXRlZA== + RGVhciA8aW5wMjp1X0ZpZWxkIG5hbWU9IkZpcnN0TmFtZSIvPiwNCg0KQSBuZXcgcGFzc3dvcmQgaGFzIGJlZW4gZ2VuZXJhdGVkIGZvciB5b3VyIHVzZXIuDQoNCk5vdyB5b3UgY2FuIGxvZ2luIHVzaW5nIHRoZSBmb2xsb3dpbmcgY3JlZGVudGlhbHM6DQoNCjxpbnAyOm1faWYgY2hlY2s9InVfRmllbGQiIG5hbWU9IlVzZXJuYW1lIj5Vc2VybmFtZTogPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPjxpbnAyOm1fZWxzZS8+RS1tYWlsOiA8aW5wMjp1X0ZpZWxkIG5hbWU9IkVtYWlsIi8+PC9pbnAyOm1faWY+IA0KUGFzc3dvcmQ6IDxpbnAyOnVfRmllbGQgbmFtZT0iUGFzc3dvcmRfcGxhaW4iLz4g + + + UmVzZXQgUGFzc3dvcmQgQ29uZmlybWF0aW9u + SGVsbG8sPGJyLz48YnIvPg0KDQpJdCBzZWVtcyB0aGF0IHlvdSBoYXZlIHJlcXVlc3RlZCBhIHBhc3N3b3JkIHJlc2V0IGZvciB5b3VyIEluLXBvcnRhbCBhY2NvdW50LiBJZiB5b3Ugd291bGQgbGlrZSB0byBwcm9jZWVkIGFuZCBjaGFuZ2UgdGhlIHBhc3N3b3JkLCBwbGVhc2UgY2xpY2sgb24gdGhlIGxpbmsgYmVsb3c6PGJyLz48YnIvPg0KDQo8YSBocmVmPSI8aW5wMjp1X0NvbmZpcm1QYXNzd29yZExpbmsgbm9fYW1wPSIxIi8+Ij48aW5wMjp1X0NvbmZpcm1QYXNzd29yZExpbmsgbm9fYW1wPSIxIi8+PC9hPjxici8+PGJyLz4NCg0KWW91IHdpbGwgcmVjZWl2ZSBhIHNlY29uZCBlbWFpbCB3aXRoIHlvdXIgbmV3IHBhc3N3b3JkIHNob3J0bHkuPGJyLz48YnIvPg0KDQpJZiB5b3UgYmVsaWV2ZSB5b3UgaGF2ZSByZWNlaXZlZCB0aGlzIGVtYWlsIGluIGVycm9yLCBwbGVhc2UgaWdub3JlIHRoaXMgZW1haWwuIFlvdXIgcGFzc3dvcmQgd2lsbCBub3QgYmUgY2hhbmdlZCB1bmxlc3MgeW91IGhhdmUgY2xpY2tlZCBvbiB0aGUgYWJvdmUgbGluay4NCg== + + + U3Vic2NyaWJlZCB0byBhIE1haWxpbmcgTGlzdCBvbiA8aW5wMjptX0Jhc2VVcmwvPg== + WW91IGhhdmUgc3Vic2NyaWJlZCB0byBhIG1haWxpbmcgbGlzdCBvbiA8aW5wMjptX0Jhc2VVcmwvPiB3ZWJzaXRlLg== + + + TmV3IFVzZXIgaGFzIFN1YnNjcmliZWQgdG8gYSBNYWxsaW5nIExpc3Q= + TmV3IHVzZXIgPGlucDI6dV9GaWVsZCBuYW1lPSJFbWFpbCIvPiBoYXMgc3Vic2NyaWJlZCB0byBhIG1haWxpbmcgbGlzdCBvbiA8YSBocmVmPSI8aW5wMjptX0Jhc2VVcmwvPiI+PGlucDI6bV9CYXNlVXJsLz48L2E+IHdlYnNpdGUu + + + Q2hlY2sgb3V0IHRoaXMgV2Vic2l0ZQ== + SGVsbG8sPC9icj48L2JyPg0KDQpUaGlzIG1lc3NhZ2UgaGFzIGJlZW4gc2VudCB0byB5b3UgZnJvbSBvbmUgb2YgeW91ciBmcmllbmRzLjwvYnI+PC9icj4NCkNoZWNrIG91dCB0aGlzIHNpdGU6IDxhIGhyZWY9IjxpbnAyOm1fQmFzZVVybC8+Ij48aW5wMjptX0Jhc2VVcmwvPjwvYT4h + + + V2Vic2l0ZSBTdWdnZXN0ZWQgdG8gYSBGcmllbmQ= + QSB2aXNpdG9yIHN1Z2dlc3RlZCA8YSBocmVmPSI8aW5wMjptX0Jhc2VVcmwvPiI+PGlucDI6bV9CYXNlVXJsLz48L2E+IHdlYnNpdGUgdG8gYSBmcmllbmQu + + + WW91IGhhdmUgYmVlbiB1bnN1YnNjcmliZWQ= + WW91IGhhdmUgc3VjY2Vzc2Z1bGx5IHVuc3Vic2NyaWJlZCBmcm9tIHRoZSBtYWlsaW5nIGxpc3Qgb24gPGEgaHJlZj0iPGlucDI6bV9CYXNlVXJsIC8+Ij48aW5wMjptX0Jhc2VVcmwgLz48L2E+IHdlYnNpdGUu + + + VXNlciBVbnN1YnNyaWJlZCBmcm9tIE1haWxpbmcgTGlzdA== + QSB1c2VyICI8aW5wMjp1X0ZpZWxkIG5hbWU9IkVtYWlsIi8+IiBoYXMgdW5zdWJzY3JpYmVkIGZyb20gdGhlIG1haWxpbmcgbGlzdCBvbiA8YSBocmVmPSI8aW5wMjptX0Jhc2VVcmwvPiI+PGlucDI6bV9CYXNlVXJsLz48L2E+Lg== + + + VXNlciBSZWdpc3RyYXRpb24gaXMgVmFsaWRhdGVk + V2VsY29tZSB0byBJbi1wb3J0YWwhPGJyLz48YnIvPg0KDQpZb3VyIHVzZXIgcmVnaXN0cmF0aW9uIGhhcyBiZWVuIGFwcHJvdmVkLiBZb3UgY2FuIGxvZ2luIG5vdyA8YSBocmVmPSI8aW5wMjptX0Jhc2VVcmwvPiI+PGlucDI6bV9CYXNlVXJsLz48L2E+IHVzaW5nIHRoZSBmb2xsb3dpbmcgaW5mb3JtYXRpb246PGJyLz48YnIvPg0KDQo9PT09PT09PT09PT09PT09PT08YnIvPg0KVXNlcm5hbWU6ICI8aW5wMjp1X0ZpZWxkIG5hbWU9IlVzZXJuYW1lIi8+Ijxici8+DQpQYXNzd29yZDogIjxpbnAyOnVfRmllbGQgbmFtZT0iUGFzc3dvcmRfcGxhaW4iLz4iPGJyLz4NCj09PT09PT09PT09PT09PT09PTxici8+PGJyLz4NCg== + + + TmV3IFVzZXIgUmVnaXN0cmF0aW9uIGlzIFZhbGlkYXRlZA== + VXNlciAiPGlucDI6dV9GaWVsZCBuYW1lPSJVc2VybmFtZSIvPiIgaGFzIGJlZW4gdmFsaWRhdGVkLg== +