Array ('self' => true), 'OnCancelEnhancement' => Array ('self' => true), 'OnExtendEnhancement' => Array ('self' => true), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Adds selected link to listing * * @param kEvent $event */ function OnProcessSelected($event) { $object = $event->getObject(); $selected_ids = $this->Application->GetVar('selected_ids'); if ($selected_ids['l']) { $link_id = $selected_ids['l']; $sql = 'SELECT ResourceId FROM '.$this->Application->getUnitOption('l', 'TableName').' WHERE '.$this->Application->getUnitOption('l', 'IDField').' = '.$link_id; $object->SetDBField($this->Application->RecallVar('dst_field'), $this->Conn->GetOne($sql)); $object->IgnoreValidation = true; // $this->RemoveRequiredFields($object); $object->Update(); } $this->finalizePopup($event); } function OnPreSaveListing($event) { $event->redirect=false; $object = $event->getObject( Array('skip_autoload' => true) ); $object->IgnoreValidation = true; // $this->RemoveRequiredFields($object); $event->CallSubEvent('OnPreSave'); $this->Application->SetVar($event->getPrefixSpecial(true).'_id', $object->GetId()); return; } /** * Occurs before updating item * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemUpdate(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(); if ( $object->IgnoreValidation ) { $object->UpdateFormattersMasterFields(); } } /** * Occurs before creating item * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeItemCreate(kEvent $event) { parent::OnBeforeItemCreate($event); /** @var kDBItem $object */ $object = $event->getObject(); if ( $object->IgnoreValidation ) { $object->UpdateFormattersMasterFields(); } } /** * Occurs before an item is deleted from live table when copying from temp * (temp handler deleted all items from live and then copy over all items from temp) * Id of item being deleted is passed as event' 'id' param * * @param kEvent $event * @return void * @access protected */ protected function OnBeforeDeleteFromLive(kEvent $event) { parent::OnBeforeDeleteFromLive($event); /** @var kDBItem $object */ $object = $event->getObject(); $sql = 'SELECT * FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ' WHERE ListingId = ' . $object->GetId(); $original_values = $this->Conn->GetRow($sql); $type_modified = ($object->GetDBField('ListingTypeId') != $original_values['ListingTypeId']); $link_modified = ($object->GetDBField('ItemResourceId') != $original_values['ItemResourceId']); $status_modified = ($object->GetDBField('Status') != $original_values['Status']); if ( $status_modified ) { $email_event = $object->GetDBField('Status') ? 'LINK.ENHANCE.APPROVE' : 'LINK.ENHANCE.DENY'; $sql = 'SELECT CreatedById FROM ' . $this->Application->getUnitOption('l', 'TableName') . ' WHERE ResourceId = ' . $object->GetDBField('ItemResourceId'); $user_id = $this->Conn->GetOne($sql); $this->Application->emailUser($email_event, $user_id); $this->Application->emailAdmin($email_event); } if ( $type_modified || $link_modified ) { $this->ResetLink($original_values); } if ( $status_modified || $type_modified || $link_modified ) { $this->EnhanceLink($object, $original_values); } if ( $status_modified && !($type_modified || $link_modified) ) { $this->ResetLink($original_values); } } function EnhanceLink(&$object, $original_values) { if ($object->GetDBField('Status') != STATUS_ACTIVE) { return false; } if ($object->GetDBField('ExpiresOn') < adodb_mktime()) { $object->SetDBField('Status', STATUS_PENDING); $object->Update(); $this->ResetLink($original_values); return false; } list($link_object, $listtype_object) = $this->UpdateLink( 'OnPurchase', $object->GetDBField('ItemResourceId'), $object->GetDBField('ListingTypeId') ); if ( $listtype_object->GetDBField('OnPurchaseAddToCatEnabled') ) { $add_to_cat = (int)$listtype_object->GetDBField('OnPurchaseAddToCat'); $sql = 'DELETE FROM '.$this->Application->getUnitOption('l-ci', 'TableName').' WHERE CategoryId = '.$add_to_cat.' AND ItemResourceId = '.$link_object->GetDBField('ResourceId').' AND PrimaryCat = 0'; $this->Conn->Query($sql); $sql = 'INSERT INTO '.$this->Application->getUnitOption('l-ci', 'TableName').' (CategoryId, ItemResourceId, PrimaryCat) VALUES ('.$add_to_cat.', '.$link_object->GetDBField('ResourceId').', 0)'; $this->Conn->Query($sql); } } function ResetLink($original_values) { static $has_been_reset = Array(); if( $original_values['Status'] != STATUS_ACTIVE || getArrayValue($has_been_reset, $original_values['ListingId']) ) { return; } $has_been_reset[$original_values['ListingId']] = 1; list (, $listtype_object) = $this->UpdateLink( 'OnExpire', $original_values['ItemResourceId'], $original_values['ListingTypeId'] ); if( $listtype_object->GetDBField('OnExpireRemoveFromCatEnabled') ) { $remove_from_cat = $listtype_object->GetDBField('OnExpireRemoveFromCat'); $sql = 'DELETE FROM '.$this->Application->getUnitOption('l-ci', 'TableName').' WHERE ItemResourceId = '.$original_values['ItemResourceId'].' AND CategoryId = '.$remove_from_cat.' AND PrimaryCat = 0'; $this->Conn->Query($sql); } } function UpdateLink($action_prefix, $resource_id, $listtype_id) { $link_object = $this->Application->recallObject('l', null, Array('skip_autoload' => true)); $link_object->Load($resource_id, 'ResourceId'); // "-item", because can be called as regular after event, and just "lst" recalls list instead $listtype_object = $this->Application->recallObject('lst.-item', null, Array('skip_autoload' => true)); $listtype_object->Load($listtype_id); $action_fields = Array( 'EdPick' => 'EditorsPick', 'New' => 'NewItem', 'Hot' => 'HotItem', 'Pop' => 'PopItem', 'Status' => 'Status', 'CustomTemplate' => 'CustomTemplate', ); // $action_prefix = 'OnPurchase'; foreach($action_fields as $action => $field) { $action_value = $listtype_object->GetDBField($action_prefix.$action); if( $action_value != 3 ) { $link_object->SetDBField($field, $action_value); } } $priority_value = $listtype_object->GetDBField($action_prefix.'PriorityValue'); switch( $listtype_object->GetDBField($action_prefix.'PriorityAction') ) { case 1: // equal $link_object->SetDBField('Priority', $priority_value); break; case 2: // increase $original_priority = $link_object->GetDBField('Priority'); $link_object->SetDBField('Priority', $original_priority + $priority_value); break; case 3: // decrease $original_priority = $link_object->GetDBField('Priority'); $link_object->SetDBField('Priority', $original_priority - $priority_value); break; default: } $link_object->Update(); return array($link_object, $listtype_object); } /** * Enter description here... * * @param kEvent $event */ function OnRequestEnhancement($event) { if ( $this->Application->prefixRegistred('ord') ) { $l_info = $this->Application->GetVar('l'); if (!$l_info) { return false; } list ($link_id, $link_info) = each($l_info); $listing_type_id = $link_info['ListingTypeId']; $listing_type = $this->Application->recallObject('lst', null, Array('skip_autoload' => true)); $listing_type->Load($listing_type_id); if ($listing_type->GetDBField('EnableBuying')) { $add_to_cart_event = new kEvent('ord:OnAddVirtualProductToCart'); $this->Application->HandleEvent($add_to_cart_event); if ($add_to_cart_event->redirect) { $event->SetRedirectParam('pass', 'm'); $event->redirect = $add_to_cart_event->redirect; } return true; } } $event->CallSubEvent('OnListingCreate'); } /** * Create listing or extend existing listing period * * @param kEvent $event */ function OnListingCreate($event) { $new_processing = false; $link_id = $listing_type_id = 0; /** @var kDBItem $object */ $object = $event->getObject( Array('skip_autoload' => true) ); switch ($event->Name) { case 'EnhanceLinkAfterOrderApprove': case 'EnhancedLinkOnCompleteOrder': // when order with listing virtual product is approved $fields = $event->getEventParam('field_values'); $item_data = unserialize($fields['ItemData']); $listing_type_id = $item_data['ListingTypeId']; $link_id = $item_data['LinkId']; $new_processing = getArrayValue($item_data, 'HasNewProcessing'); break; case 'OnListingCreate': // when requesting enhancement from front (and not via in-commerce) $links_info = $this->Application->GetVar('l'); if (!$links_info) return false; $event->redirect = false; list($link_id, $link_info) = each($links_info); $listing_type_id = $link_info['ListingTypeId']; $new_processing = false; break; } if (!$listing_type_id) { // free or invalid listing type selected return false; } // get resource_id of link beeing enhanced $sql = 'SELECT ResourceId FROM '.$this->Application->getUnitOption('l', 'TableName').' WHERE LinkId = '.$link_id; $resource_id = $this->Conn->GetOne($sql); // get listing by link's resource_id $object->Load($resource_id, 'ItemResourceId'); if ($object->isLoaded()) { $original_values = $object->GetFieldValues(); } else { // set initial fields to listing $object->SetDBField('ListingTypeId', $listing_type_id); $object->SetDBField('ItemResourceId', $resource_id); if ($event->Name == 'OnListingCreate' || $new_processing) { $item_status = STATUS_PENDING; } else { $item_status = STATUS_ACTIVE; } $object->SetDBField('Status', $item_status); } // set date of purchase for new listings $purchased_on = max(adodb_mktime(), $object->GetDBField('ExpiresOn')); if (!$object->isLoaded()) { $object->SetDBField('PurchasedOn_date', $purchased_on); $object->SetDBField('PurchasedOn_time', $purchased_on); } // set expiration time for listing $listing_type = $this->Application->recallObject('lst', null, Array('skip_autoload' => true)); $listing_type->Load($listing_type_id); $dur_type_mapping = Array( 1 => 1, 2 => 60, 3 => 3600, 4 => 3600*24, 5 => 3600*24*7, 6 => 3600*24*365/12, 7 => 3600*24*365 ); $duration = $listing_type->GetDBField('Duration'); $duration_type = $listing_type->GetDBField('DurationType'); $expiration_interval = $duration * $dur_type_mapping[$duration_type]; $expiration_date = $purchased_on + $expiration_interval; $object->SetDBField('ExpiresOn_date', $expiration_date); $object->SetDBField('ExpiresOn_time', $expiration_date); // when extending enhancement mark listing as non-received renewal reminder $object->SetDBField('RenewalReminderSent', 0); $action = $object->isLoaded() ? 'Update' : 'Create'; if ($object->$action()) { $event->status = kEvent::erSUCCESS; switch ($event->Name) { case 'EnhanceLinkAfterOrderApprove': case 'EnhancedLinkOnCompleteOrder': // when order with listing virtual product is approved if (getArrayValue($original_values, 'Status') != STATUS_ACTIVE) { $this->EnhanceLink($object, Array()); } break; case 'OnListingCreate': // when requesting enhancement from front (and not via in-commerce) $event->redirect = $this->Application->GetVar('success_template'); $sql = 'SELECT CreatedById FROM '.$this->Application->getUnitOption('l', 'TableName').' WHERE ResourceId = '.$object->GetDBField('ItemResourceId'); $this->Application->emailUser('LINK.ENHANCE', $this->Conn->GetOne($sql)); $this->Application->emailAdmin('LINK.ENHANCE'); break; } } else { $event->status = kEvent::erFAIL; } } /** * Enter description here... * * @param kEvent $event */ function EnhancedLinkOnCompleteOrder($event) { // create enhancement, but pending $this->OnListingCreate($event); // save created listing_id back to itemdata $object = $event->getObject( Array('skip_autoload' => true) ); $fields = $event->getEventParam('field_values'); $item_data = unserialize($fields['ItemData']); unset($item_data['ListingTypeId']); $item_data['ListingId'] = $object->GetID(); $orditems_idfield = $this->Application->getUnitOption('orditems', 'IDField'); $orditems_table = $this->Application->getUnitOption('orditems', 'TableName'); $this->Conn->doUpdate( Array('ItemData' => serialize($item_data)), $orditems_table, $orditems_idfield.' = '.$fields['OrderItemId'] ); } /** * Enter description here... * * @param kEvent $event */ function EnhanceLinkAfterOrderApprove($event) { /** @var kDBItem $object */ $object = $event->getObject( Array('skip_autoload' => true) ); $fields = $event->getEventParam('field_values'); $item_data = unserialize($fields['ItemData']); if ( getArrayValue($item_data, 'HasNewProcessing') ) { // new processing: just approve created listing here $listing_id = $item_data['ListingId']; $object->Load($listing_id); // moved enhancement period to time admin approved enhancement $time_diff = adodb_mktime() - $object->GetDBField('PurchasedOn'); $object->SetDBField('PurchasedOn_date', $object->GetDBField('PurchasedOn_date') + $time_diff); $object->SetDBField('PurchasedOn_time', $object->GetDBField('PurchasedOn_time') + $time_diff); $object->SetDBField('ExpiresOn_date', $object->GetDBField('ExpiresOn_date') + $time_diff); $object->SetDBField('ExpiresOn_time', $object->GetDBField('ExpiresOn_time') + $time_diff); $object->SetDBField('Status', STATUS_ACTIVE); $object->Update(); $this->EnhanceLink($object, Array()); return true; } else { // create listing & approve it at the same time $this->OnListingCreate($event); } } /** * Delete listing * * @param kEvent $event */ function EnhanceLinkAfterOrderDeny($event) { $object = $event->getObject( Array('skip_autoload' => true) ); $fields = $event->getEventParam('field_values'); $item_data = unserialize($fields['ItemData']); $listing_id = $item_data['ListingId']; $temp_handler = $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler'); $temp_handler->DeleteItems($event->Prefix, $event->Special, Array($listing_id)); } /** * Enter description here... * * @param kEvent $event */ function ExpireLink($event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $fields = $event->getEventParam('field_values'); $item_data = unserialize($fields['ItemData']); $sql = 'SELECT ListingId FROM ' . $this->Application->getUnitOption($event->Prefix, 'TableName') . ' WHERE ItemResourceId = ' . $item_data['LinkId']; $listing_id = $this->Conn->GetOne($sql); $object->Load($listing_id); $original_values = $object->GetFieldValues(); $object->SetDBField('Status', 2); if ( $object->Update() ) { $event->status = kEvent::erSUCCESS; $this->ResetLink($original_values); } else { $event->status = kEvent::erFAIL; } } /** * Apply same processing to each item being selected in grid * * @param kEvent $event * @return void * @access protected */ protected function iterateItems(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $ids = $this->StoreSelectedIDs($event); if ( $event->Name == 'OnMassApprove' ) { foreach ($ids as $id) { $object->Load($id); if ( $object->GetDBField('Status') != STATUS_ACTIVE ) { $original_values = $object->GetFieldValues(); $object->SetDBField('Status', STATUS_ACTIVE); $this->EnhanceLink($object, $original_values); } } } if ( $event->Name == 'OnMassDecline' ) { foreach ($ids as $id) { $object->Load($id); if ( $object->GetDBField('Status') == STATUS_ACTIVE ) { $original_values = $object->GetFieldValues(); $this->ResetLink($original_values); $sql = 'SELECT CreatedById FROM ' . $this->Application->getUnitOption('l', 'TableName') . ' WHERE ResourceId = ' . $object->GetDBField('ItemResourceId'); $this->Application->emailUser('LINK.ENHANCE.DENY', $this->Conn->GetOne($sql)); $this->Application->emailAdmin('LINK.ENHANCE.DENY'); } } } parent::iterateItems($event); // extend period for pending/renewal links (if owner has agreed) if ( $event->Name == 'OnMassApprove' ) { /** @var kDBItem $lst_object */ $lst_object = $this->Application->recallObject('lst', null, Array ('skip_autoload' => true)); foreach ($ids as $id) { $object->Load($id); $sql = 'SELECT CreatedById FROM ' . $this->Application->getUnitOption('l', 'TableName') . ' WHERE ResourceId = ' . $object->GetDBField('ItemResourceId'); $owner_id = $this->Conn->GetOne($sql); if ( $object->GetDBField('PendingRenewal') == 1 ) { $lst_object->Load( $object->GetDBField('ListingTypeId') ); $dur_type_mapping = Array ( 1 => 1, 2 => 60, 3 => 3600, 4 => 3600 * 24, 5 => 3600 * 24 * 7, 6 => 3600 * 24 * 365 / 12, 7 => 3600 * 24 * 365 ); $duration = $lst_object->GetDBField('Duration'); $duration_type = $lst_object->GetDBField('DurationType'); $expiration_interval = $duration * $dur_type_mapping[$duration_type]; $renewal_begins = max(adodb_mktime(), $object->GetDBField('ExpiresOn')); $expiration_date = $renewal_begins + $expiration_interval; $object->SetDBField('ExpiresOn_date', $expiration_date); $object->SetDBField('ExpiresOn_time', $expiration_date); $object->SetDBField('RenewalReminderSent', 0); $object->SetDBField('PendingRenewal', 0); if ( $object->Update() ) { $event->SetRedirectParam('opener', 's'); $this->Application->emailUser('LINK.ENHANCE.RENEW', $owner_id); $this->Application->emailAdmin('LINK.ENHANCE.RENEW'); } } else { $this->Application->emailUser('LINK.ENHANCE.APPROVE', $owner_id); $this->Application->emailAdmin('LINK.ENHANCE.APPROVE'); } } } } /** * Redirects to cancel template on front-end * * @param kEvent $event * @return void * @access protected */ protected function OnCancel(kEvent $event) { parent::OnCancel($event); if ( !$this->Application->isAdmin ) { $event->SetRedirectParam('opener', 's'); $event->redirect = $this->Application->GetVar('cancel_template'); } } /** * Checks that user is owner of link & returns listing id if permissions are ok * * @param kEvent $event * @return mixed */ function verifyListingOwner($event) { $link_id = $this->Application->GetVar('l_id'); $user_id = $this->Application->RecallVar('user_id'); $sql = 'SELECT ResourceId FROM '.$this->Application->getUnitOption('l', 'TableName').' WHERE (LinkId = '.$link_id.') AND (CreatedById = '.$user_id.')'; $resource_id = $this->Conn->GetOne($sql); if (!$resource_id) { $event->status = kEvent::erFAIL; return false; } $sql = 'SELECT ListingId FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').' WHERE ItemResourceId = '.$resource_id; return $this->Conn->GetOne($sql); } function OnExtendEnhancement($event) { $listing_id = $this->verifyListingOwner($event); if (!$listing_id) { return ; } $object = $event->getObject( Array('skip_autoload' => true) ); $object->Load($listing_id); $object->SetDBField('PendingRenewal', 1); $object->Update(); $event->redirect = $this->Application->GetVar('success_template'); $sql = 'SELECT CreatedById FROM '.$this->Application->getUnitOption('l', 'TableName').' WHERE ResourceId = '.$object->GetDBField('ItemResourceId'); $this->Application->emailUser('LINK.ENHANCE.EXTEND', $this->Conn->GetOne($sql)); $this->Application->emailAdmin('LINK.ENHANCE.EXTEND'); } /** * Cancels enhancement * * @param kEvent $event */ function OnCancelEnhancement($event) { $listing_id = $this->verifyListingOwner($event); if ( !$listing_id ) { return; } /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $object->Load($listing_id); $original_values = $object->GetFieldValues(); $original_values['Status'] = 1; $this->ResetLink($original_values); $sql = 'SELECT CreatedById FROM ' . $this->Application->getUnitOption('l', 'TableName') . ' WHERE ResourceId = ' . $object->GetDBField('ItemResourceId'); $this->Application->emailUser('LINK.ENHANCE.CANCEL', $this->Conn->GetOne($sql)); $this->Application->emailAdmin('LINK.ENHANCE.CANCEL'); $object->Delete(); $event->redirect = $this->Application->GetVar('success_template'); } /** * Checks expired paid listings * * @param kEvent $event */ function OnCheckExpiredPaidListings($event) { $sql = 'SELECT ListingId FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').' WHERE ExpiresOn < '.adodb_mktime().' AND Status = 1'; $expired_listings = $this->Conn->GetCol($sql); if(is_array($expired_listings) && count($expired_listings) > 0) { /** @var kDBItem $object */ $object = $this->Application->recallObject($event->Prefix.'.-item', null, Array('skip_autoload' => true)); foreach($expired_listings as $listing_id) { $object->Load($listing_id); $original_values = $object->GetFieldValues(); $this->ResetLink($original_values); $object->SetDBField('Status', 2); $object->Update(); $sql = 'SELECT CreatedById FROM '.$this->Application->getUnitOption('l', 'TableName').' WHERE ResourceId = '.$object->GetDBField('ItemResourceId'); $this->Application->emailUser('LINK.ENHANCE.EXPIRE', $this->Conn->GetOne($sql)); $this->Application->emailAdmin('LINK.ENHANCE.EXPIRE'); } } $sql = 'SELECT ls.ListingId, l.CreatedById FROM '.$this->Application->getUnitOption($event->Prefix, 'TableName').' ls LEFT JOIN '.$this->Application->getUnitOption('lst', 'TableName').' lst ON ls.ListingTypeId = lst.ListingTypeId LEFT JOIN '.$this->Application->getUnitOption('l', 'TableName').' l ON ls.ItemResourceId = l.ResourceId WHERE ls.Status = 1 AND ls.ExpiresOn < '.adodb_mktime().' + lst.RenewalReminder * 3600 *24 AND ls.RenewalReminderSent = 0'; $res = $this->Conn->Query($sql); if(is_array($res) && count($res) > 0) { $listing_ids = Array(); foreach($res as $record) { $this->Application->emailUser('LINK.ENHANCE.RENEWAL.NOTICE', $record['CreatedById']); $this->Application->emailAdmin('LINK.ENHANCE.RENEWAL.NOTICE'); $listing_ids[] = $record['ListingId']; } $sql = 'UPDATE '.$this->Application->getUnitOption($event->Prefix, 'TableName').' SET RenewalReminderSent = 1 WHERE ListingId IN ('.implode(',', $listing_ids).')'; $this->Conn->Query($sql); } } /** * Removes enhancements on listing delete * * @param kEvent $event * @return void * @access protected */ protected function OnMassDelete(kEvent $event) { /** @var kDBItem $object */ $object = $event->getObject(Array ('skip_autoload' => true)); $ids = $this->StoreSelectedIDs($event); foreach ($ids as $id) { $object->Load($id); if ( $object->GetDBField('Status') == STATUS_ACTIVE ) { $this->ResetLink( $object->GetFieldValues() ); } } parent::OnMassDelete($event); } /** * Moves enhancement from original link to it's pending copy, that is going to be approved * * @param kEvent $event */ function OnMoveEnhancement($event) { $id_field = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'IDField'); $item_table_name = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'TableName'); $pending_id = $event->MasterEvent->getEventParam('id'); $original_id = $event->MasterEvent->getEventParam('original_id'); $sql = 'SELECT ResourceId, '.$id_field.' FROM '.$item_table_name.' WHERE '.$id_field.' IN ('.$pending_id.','.$original_id.')'; $resource_ids = $this->Conn->GetCol($sql, $id_field); $table_name = $this->Application->getUnitOption($event->Prefix, 'TableName'); $sql = 'UPDATE '.$table_name.' SET ItemResourceId = '.$resource_ids[$pending_id].' WHERE ItemResourceId = '.$resource_ids[$original_id]; $this->Conn->Query($sql); } /** * Makes calculated fields to go to multilingual link fields * * @param kEvent $event * @return void * @access protected */ protected function OnAfterConfigRead(kEvent $event) { parent::OnAfterConfigRead($event); $language_id = $this->Application->GetVar('m_lang'); $calculated_fields = $this->Application->getUnitOption($event->Prefix, 'CalculatedFields'); $calculated_fields['']['LinkName'] = 'CONCAT(item_table.l' . $language_id . '_Name, " (", item_table.Url, ")")'; $this->Application->setUnitOption($event->Prefix, 'CalculatedFields', $calculated_fields); } }