function getCMSFields()
 {
     $fields = parent::getCMSFields();
     $fieldLabels = $this->Config()->get("field_labels");
     $fields->replaceField("CountryCode", new DropDownField("CountryCode", $fieldLabels["CountryCode"], EcommerceCountry::get_country_dropdown()));
     return $fields;
 }
コード例 #2
0
 function run($request)
 {
     $count = 0;
     $array = Geoip::getCountryDropDown();
     foreach ($array as $key => $value) {
         if (!DataObject::get_one("EcommerceCountry", "\"Code\" = '" . Convert::raw2sql($key) . "'")) {
             $obj = new EcommerceCountry();
             $obj->Code = $key;
             $obj->Name = $value;
             $obj->write();
             DB::alteration_message("adding {$value} to Ecommerce Country", "created");
             $count++;
         }
     }
     DB::alteration_message("{$count} countries created");
 }
 public function getCMSFields()
 {
     $fields = parent::getCMSFields();
     $fields->replaceField("From", $from = new DateField("From", "Valid From - add any date and time"));
     $fields->replaceField("Until", $until = new DateField("Until", "Valid Until - add any date and time"));
     $fields->replaceField("NewPrice", new CurrencyField("NewPrice", "PRICE (OPTION 1 / 3) - only enter if there is a set new price independent of the 'standard' price."));
     $fields->replaceField("Percentage", new NumericField("Percentage", "PERCENTAGE (OPTIONAL 2/ 3) discount from 0 (0% discount) to 100 (100% discount)."));
     $fields->replaceField("Reduction", new CurrencyField("Reduction", "REDUCTION (OPTION 3 /3 ) - e.g. if you enter 2.00 then the new price will be the standard product price minus 2."));
     if (!$this->ID) {
         $fields->addFieldToTab("Root.Main", new LiteralField("SaveFirst", "<p>Please save first - and then select security groups / countries</p>"));
         $fields->removeByName("NoLongerValid");
     }
     if ($groups = Group::get()->count()) {
         $groups = Group::get();
         $fields->replaceField("Groups", new CheckboxSetField("Groups", "Who", $groups->map()->toArray()));
     } else {
         $fields->removeByName("Groups");
     }
     if ($ecommerceCountries = EcommerceCountry::get()) {
         $fields->replaceField("EcommerceCountries", new CheckboxSetField("EcommerceCountries", "Where", $ecommerceCountries->map()->toArray()));
     } else {
         $fields->removeByName("EcommerceCountries");
     }
     if (DiscountCouponOption::get()->count()) {
         $fields->replaceField("DiscountCouponOptions", new CheckboxSetField("DiscountCouponOptions", "Discount Coupons", DiscountCouponOption::get()->map()->toArray()));
     } else {
         $fields->removeByName("DiscountCouponOptions");
     }
     $from->setConfig('showcalendar', true);
     $until->setConfig('showcalendar', true);
     return $fields;
 }
 /**
  * This is called from /ecommerce/code/Product
  * returning NULL is like returning TRUE, i.e. ignore this.
  * @param Member $member
  * @return FALSE | NULL
  */
 function canPurchaseByCountry(Member $member = null, $checkPrice = true)
 {
     if ($this->owner->AllCountries) {
         return null;
     }
     $countryCode = EcommerceCountry::get_country();
     if ($countryCode) {
         $included = $this->owner->getManyManyComponents('IncludedCountries', "\"Code\" = '{$countryCode}'")->Count();
         if ($included) {
             return null;
         }
         $excluded = $this->owner->getManyManyComponents('ExcludedCountries', "\"Code\" = '{$countryCode}'")->Count();
         if ($excluded) {
             return false;
         }
     }
     return null;
 }
コード例 #5
0
 /**
  * This function returns back the default list of regions, filtered by the currently selected country.
  * @return Array - array of CountryCode => Country
  **/
 protected static function get_default_array()
 {
     $defaultArray = array();
     $regions = DataObject::get("EcommerceRegion", "\"DoNotAllowSales\" <> 1 AND \"CountryID\"  = '" . EcommerceCountry::get_country_id() . "'");
     if ($regions) {
         foreach ($regions as $region) {
             $defaultArray[$region->Code] = $region->Name;
         }
     }
     return $defaultArray;
 }
コード例 #6
0
 public function getFixedCountry()
 {
     $code = EcommerceCountry::get_fixed_country_code();
     if ($code) {
         return EcommerceCountry::find_title($code);
     }
     return "";
 }
 protected function checkGEOIP()
 {
     if (Config::inst()->get("EcommerceCountry", "visitor_country_provider") == "EcommerceCountry_VisitorCountryProvider" && !class_exists("Geoip")) {
         user_error("\r\n\t\t\t\tYou need to install Geoip module that has a method Geoip::visitor_country, returning the country code associated with the user's IP address.\r\n\t\t\t\tAlternatively you can set the following config EcommerceCountry.visitor_country_provider to something like MyGEOipProvider.\r\n\t\t\t\tYou then create a class MyGEOipProvider with a method getCountry().", E_USER_NOTICE);
     } elseif (Director::isLive() && !EcommerceCountry::get_country_from_ip()) {
         user_error("\r\n\t\t\t\tPlease make sure that '" . $this->Config()->get("visitor_country_provider") . "' (visitor_country_provider) is working on your server (see the GEOIP module for details).", E_USER_NOTICE);
     }
 }
コード例 #8
0
 function getShippingFullCountryName()
 {
     return EcommerceCountry::find_title($this->ShippingCountry);
 }
コード例 #9
0
 /**
  * standard SS method
  * sets the country to the best known country {@link EcommerceCountry}
  **/
 function populateDefaults()
 {
     parent::populateDefaults();
     $this->ShippingCountry = EcommerceCountry::get_country();
 }
コード例 #10
0
 /**
  * takes the defaultArray and limits it with "only show" and "do not show" value, relevant for the current order.
  * @return Array (Code, Title)
  **/
 public static function list_of_allowed_entries_for_dropdown()
 {
     if (!self::$list_of_allowed_entries_for_dropdown_array) {
         $defaultArray = self::get_default_array();
         $onlyShow = self::$for_current_order_only_show_countries;
         $doNotShow = self::$for_current_order_do_not_show_countries;
         if (is_array($onlyShow) && count($onlyShow)) {
             foreach ($defaultArray as $key => $value) {
                 if (!in_array($key, $onlyShow)) {
                     unset($defaultArray[$key]);
                 }
             }
         }
         if (is_array($doNotShow) && count($doNotShow)) {
             foreach ($doNotShow as $code) {
                 if (isset($defaultArray[$code])) {
                     unset($defaultArray[$code]);
                 }
             }
         }
         self::$list_of_allowed_entries_for_dropdown_array = $defaultArray;
     }
     return self::$list_of_allowed_entries_for_dropdown_array;
 }
コード例 #11
0
 /**
  * put together a dropdown for the country field
  * @param String $name - name of the field
  * @return DropdownField
  **/
 protected function getCountryField($name)
 {
     $countriesForDropdown = EcommerceCountry::list_of_allowed_entries_for_dropdown();
     $countryField = new DropdownField($name, EcommerceCountry::i18n_singular_name(), $countriesForDropdown, EcommerceCountry::get_country());
     if (count($countriesForDropdown) < 2) {
         $countryField = $countryField->performReadonlyTransformation();
         if (count($countriesForDropdown) < 1) {
             $countryField = new HiddenField($name, '', "not available");
         }
     }
     $prefix = EcommerceConfig::get("OrderAddress", "field_class_and_id_prefix");
     $countryField->addExtraClass($prefix . 'ajaxCountryField');
     return $countryField;
 }
 function run($request)
 {
     $count = 0;
     $array = EcommerceCountry::get_country_dropdown();
     $allowedArray = EcommerceCountry::get()->filter(array("DoNotAllowSales" => 1));
     if ($allowedArray->count()) {
         foreach ($allowedArray as $obj) {
             $obj->DoNotAllowSales = 0;
             $obj->write();
             DB::alteration_message("Disallowing sales to " . $obj->Name);
         }
     } else {
         DB::alteration_message("Could not find any countries that are not allowed", "created");
     }
 }
コード例 #13
0
 /**
  * Produces a debug of the shopping cart.
  */
 public function debug()
 {
     if (Director::isDev() || Permission::check("ADMIN")) {
         debug::show($this->currentOrder());
         echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Country</h1>";
         echo "GEOIP Country: " . EcommerceCountry::get_country_from_ip() . "<br />";
         echo "Calculated Country Country: " . EcommerceCountry::get_country() . "<br />";
         echo "<blockquote><blockquote><blockquote><blockquote>";
         echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Items</h1>";
         $items = $this->currentOrder()->Items();
         echo $items->sql();
         echo "<hr />";
         if ($items->count()) {
             foreach ($items as $item) {
                 Debug::show($item);
             }
         } else {
             echo "<p>there are no items for this order</p>";
         }
         echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Modifiers</h1>";
         $modifiers = $this->currentOrder()->Modifiers();
         if ($modifiers->count()) {
             foreach ($modifiers as $modifier) {
                 Debug::show($modifier);
             }
         } else {
             echo "<p>there are no modifiers for this order</p>";
         }
         echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Addresses</h1>";
         $billingAddress = $this->currentOrder()->BillingAddress();
         if ($billingAddress && $billingAddress->exists()) {
             Debug::show($billingAddress);
         } else {
             echo "<p>there is no billing address for this order</p>";
         }
         $shippingAddress = $this->currentOrder()->ShippingAddress();
         if ($shippingAddress && $shippingAddress->exists()) {
             Debug::show($shippingAddress);
         } else {
             echo "<p>there is no shipping address for this order</p>";
         }
         $currencyUsed = $this->currentOrder()->CurrencyUsed();
         if ($currencyUsed && $currencyUsed->exists()) {
             echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Currency</h1>";
             Debug::show($currencyUsed);
         }
         $cancelledBy = $this->currentOrder()->CancelledBy();
         if ($cancelledBy && $cancelledBy->exists()) {
             echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Cancelled By</h1>";
             Debug::show($cancelledBy);
         }
         $logs = $this->currentOrder()->OrderStatusLogs();
         if ($logs && $logs->count()) {
             echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Logs</h1>";
             foreach ($logs as $log) {
                 Debug::show($log);
             }
         }
         $payments = $this->currentOrder()->Payments();
         if ($payments && $payments->count()) {
             echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Payments</h1>";
             foreach ($payments as $payment) {
                 Debug::show($payment);
             }
         }
         $emails = $this->currentOrder()->Emails();
         if ($emails && $emails->count()) {
             echo "<hr /><hr /><hr /><hr /><hr /><hr /><h1>Emails</h1>";
             foreach ($emails as $email) {
                 Debug::show($email);
             }
         }
         echo "</blockquote></blockquote></blockquote></blockquote>";
     } else {
         echo "Please log in as admin first";
     }
 }
コード例 #14
0
 public function getCountryName()
 {
     return EcommerceCountry::find_title($this->CountryCode);
 }
コード例 #15
0
 /**
  * This function returns back the default list of regions, filtered by the currently selected country.
  * @return Array - array of Region.ID => Region.Name
  **/
 protected static function get_default_array()
 {
     $defaultArray = array();
     $regions = EcommerceRegion::get()->Exclude(array("DoNotAllowSales" => 1));
     $defaultRegion = EcommerceCountry::get_country_id();
     if ($defaultRegion) {
         $regions = $regions->Filter(array("CountryID" => EcommerceCountry::get_country_id()));
     }
     if ($regions && $regions->count()) {
         foreach ($regions as $region) {
             $defaultArray[$region->ID] = $region->Name;
         }
     }
     return $defaultArray;
 }
コード例 #16
0
 /**
  * Returns the most likely country for the sale.
  * @return String
  */
 protected function LiveCountry()
 {
     return EcommerceCountry::get_country();
 }
 function updateCalculatedPrice(&$startingPrice)
 {
     $newPrice = -1;
     $fieldName = $this->owner->ClassName . "ID";
     $singleton = ComplexPriceObject::get()->first();
     if ($singleton) {
         // Check that ComplexPriceObject can be joined to this type of object
         if (!$singleton->hasField($fieldName)) {
             $ancestorArray = ClassInfo::ancestry($this->owner, true);
             foreach ($ancestorArray as $ancestor) {
                 $fieldName = $ancestor . "ID";
                 if ($singleton->hasField($fieldName)) {
                     break;
                 }
             }
         }
         // Load up the alternate prices for this product
         $prices = ComplexPriceObject::get()->filter(array($fieldName => $this->owner->ID, "NoLongerValid" => 0))->sort("NewPrice", "DESC");
         $memberGroupsArray = array();
         if ($prices->count()) {
             // Load up the groups for the current memeber, if any
             if ($member = Member::currentUser()) {
                 if ($memberGroupComponents = $member->getManyManyComponents('Groups')) {
                     if ($memberGroupComponents && $memberGroupComponents->count()) {
                         $memberGroupsArray = $memberGroupComponents->column("ID");
                         if (!is_array($memberGroupsArray)) {
                             $memberGroupsArray = array();
                         }
                     }
                 }
             }
             $countryID = EcommerceCountry::get_country_id();
             // Look at each price and see if it can be used
             foreach ($prices as $price) {
                 $priceCanBeUsed = true;
                 // Does it pass the group filter?
                 if ($priceGroupComponents = $price->getManyManyComponents('Groups')) {
                     if ($priceGroupComponents && $priceGroupComponents->count()) {
                         $priceCanBeUsed = false;
                         $priceGroupArray = $priceGroupComponents->column("ID");
                         if (!is_array($priceGroupArray)) {
                             $priceGroupArray = array();
                         }
                         $interSectionArray = array_intersect($priceGroupArray, $memberGroupsArray);
                         if (is_array($interSectionArray) && count($interSectionArray)) {
                             $priceCanBeUsed = true;
                         }
                     }
                 }
                 // Does it pass the country filter?
                 if ($priceCanBeUsed) {
                     if ($priceCountryComponents = $price->getManyManyComponents('EcommerceCountries')) {
                         if ($priceCountryComponents && $priceCountryComponents->count()) {
                             $priceCanBeUsed = false;
                             $priceCountryArray = $priceCountryComponents->column("ID");
                             if (!is_array($priceCountryArray)) {
                                 $priceCountryArray = array();
                             }
                             if ($countryID && in_array($countryID, $priceCountryArray)) {
                                 $priceCanBeUsed = true;
                             }
                         }
                     }
                 }
                 // Does it pass the date filter?
                 if ($priceCanBeUsed) {
                     $nowTS = strtotime("now");
                     if ($price->From) {
                         $priceCanBeUsed = false;
                         $fromTS = strtotime($price->From);
                         if ($fromTS && $fromTS < $nowTS) {
                             $priceCanBeUsed = true;
                         }
                     }
                 }
                 if ($priceCanBeUsed) {
                     if ($price->Until) {
                         $priceCanBeUsed = false;
                         $untilTS = strtotime($price->Until);
                         if ($untilTS && $untilTS > $nowTS) {
                             $priceCanBeUsed = true;
                         }
                     }
                 }
                 // If so, apply the price
                 if ($priceCanBeUsed) {
                     $newPrice = $price->getCalculatedPrice();
                 }
             }
         }
     }
     if ($newPrice > -1) {
         $startingPrice = $newPrice;
     }
     return $startingPrice;
 }
コード例 #18
0
 function getFullCountryName()
 {
     return EcommerceCountry::find_title($this->Country);
 }
 /**
  * description of region and country being shipped to.
  * @return String
  */
 protected function LiveRegionAndCountry()
 {
     $details = array();
     $option = $this->Option();
     if ($option) {
         $regionID = EcommerceRegion::get_region_id();
         if ($regionID) {
             $region = EcommerceRegion::get()->byID($regionID);
             if ($region) {
                 $details[] = $region->Name;
             }
         }
         $countryID = EcommerceCountry::get_country_id();
         if ($countryID) {
             $country = EcommerceCountry::get()->byID($countryID);
             if ($country) {
                 $details[] = $country->Name;
             }
         }
     } else {
         return _t("PickUpOrDeliveryModifier.NOTSELECTED", "No delivery option has been selected");
     }
     if (count($details)) {
         return implode(", ", $details);
     }
 }
コード例 #20
0
 public function debug()
 {
     $html = EcommerceTaskDebugCart::debug_object($this);
     $html .= "<ul>";
     $html .= "<li><hr />Links<hr /></li>";
     $html .= "<li><b>Link:</b> <a href=\"" . $this->Link() . "\">" . $this->Link() . "</a></li>";
     $html .= "<li><b>Ajax Link:</b> <a href=\"" . $this->AjaxLink() . "\">" . $this->AjaxLink() . "</a></li>";
     $html .= "<li><b>AddVariations Link:</b> <a href=\"" . $this->AddVariationsLink() . "\">" . $this->AddVariationsLink() . "</a></li>";
     $html .= "<li><b>Add to Cart Link:</b> <a href=\"" . $this->AddLink() . "\">" . $this->AddLink() . "</a></li>";
     $html .= "<li><b>Increment Link:</b> <a href=\"" . $this->IncrementLink() . "\">" . $this->IncrementLink() . "</a></li>";
     $html .= "<li><b>Decrement Link:</b> <a href=\"" . $this->DecrementLink() . "\">" . $this->DecrementLink() . "</a></li>";
     $html .= "<li><b>Remove Link:</b> <a href=\"" . $this->RemoveAllLink() . "\">" . $this->RemoveLink() . "</a></li>";
     $html .= "<li><b>Remove All Link:</b> <a href=\"" . $this->RemoveAllLink() . "\">" . $this->RemoveAllLink() . "</a></li>";
     $html .= "<li><b>Remove All and Edit Link:</b> <a href=\"" . $this->RemoveAllAndEditLink() . "\">" . $this->RemoveAllAndEditLink() . "</a></li>";
     $html .= "<li><b>Set Specific Quantity Item Link (e.g. 77):</b> <a href=\"" . $this->SetSpecificQuantityItemLink(77) . "\">" . $this->SetSpecificQuantityItemLink(77) . "</a></li>";
     $html .= "<li><hr />Cart<hr /></li>";
     $html .= "<li><b>Allow Purchase (DB Value):</b> " . $this->AllowPurchaseNice() . " </li>";
     $html .= "<li><b>Can Purchase (overal calculation):</b> " . ($this->canPurchase() ? "YES" : "NO") . " </li>";
     $html .= "<li><b>Shop Open:</b> " . ($this->EcomConfig() ? $this->EcomConfig()->ShopClosed ? "NO" : "YES" : "NO CONFIG") . " </li>";
     $html .= "<li><b>Extended Country Can Purchase:</b> " . ($this->extendedCan('canPurchaseByCountry', null) === null ? "no applicable" : ($this->extendedCan('canPurchaseByCountry', null) ? "CAN PURCHASE" : "CAN NOT PURCHASE")) . " </li>";
     $html .= "<li><b>Allow sales to this country (" . EcommerceCountry::get_country() . "):</b> " . (EcommerceCountry::allow_sales() ? "YES" : "NO") . " </li>";
     $html .= "<li><b>Class Name for OrderItem:</b> " . $this->classNameForOrderItem() . " </li>";
     $html .= "<li><b>Quantity Decimals:</b> " . $this->QuantityDecimals() . " </li>";
     $html .= "<li><b>Is In Cart:</b> " . ($this->IsInCart() ? "YES" : "NO") . " </li>";
     $html .= "<li><b>Has Been Sold:</b> " . ($this->HasBeenSold() ? "YES" : "NO") . " </li>";
     $html .= "<li><b>Calculated Price:</b> " . $this->CalculatedPrice() . " </li>";
     $html .= "<li><b>Calculated Price as Money:</b> " . $this->getCalculatedPriceAsMoney()->Nice() . " </li>";
     $html .= "<li><hr />Location<hr /></li>";
     $html .= "<li><b>Main Parent Group:</b> " . $this->MainParentGroup()->Title . "</li>";
     $html .= "<li><b>All Others Parent Groups:</b> " . ($this->AllParentGroups()->count() ? "<pre>" . print_r($this->AllParentGroups()->map()->toArray(), 1) . "</pre>" : "none") . "</li>";
     $html .= "<li><hr />Image<hr /></li>";
     $html .= "<li><b>Image:</b> " . ($this->BestAvailableImage() ? "<img src=" . $this->BestAvailableImage()->Link() . " />" : "no image") . " </li>";
     $productGroup = ProductGroup::get()->byID($this->ParentID);
     if ($productGroup) {
         $html .= "<li><hr />Product Example<hr /></li>";
         $html .= "<li><b>Product Group View:</b> <a href=\"" . $productGroup->Link() . "\">" . $productGroup->Title . "</a> </li>";
         $html .= "<li><b>Product Group Debug:</b> <a href=\"" . $productGroup->Link("debug") . "\">" . $productGroup->Title . "</a> </li>";
         $html .= "<li><b>Product Group Admin:</b> <a href=\"" . "/admin/pages/edit/show/" . $productGroup->ID . "\">" . $productGroup->Title . " Admin</a> </li>";
         $html .= "<li><b>Edit this Product:</b> <a href=\"" . "/admin/pages/edit/show/" . $this->ID . "\">" . $this->Title . " Admin</a> </li>";
     }
     $html .= "</ul>";
     return $html;
     $html .= "</ul>";
     return $html;
 }
コード例 #21
0
 /**
  * put together a dropdown for the country field
  *
  * @param String $name - name of the field
  * @return DropdownField
  **/
 protected function getCountryField($name)
 {
     $countriesForDropdown = EcommerceCountry::list_of_allowed_entries_for_dropdown();
     $title = _t("OrderAddress." . strtoupper($name), "Country");
     $countryField = new DropdownField($name, $title, $countriesForDropdown, EcommerceCountry::get_country());
     $countryField->setRightTitle(_t("OrderAddress." . strtoupper($name) . "_RIGHT", ""));
     if (count($countriesForDropdown) < 2) {
         $countryField = $countryField->performReadonlyTransformation();
         if (count($countriesForDropdown) < 1) {
             $countryField = new HiddenField($name, '', "not available");
         }
     }
     $prefix = EcommerceConfig::get("OrderAddress", "field_class_and_id_prefix");
     $countryField->addExtraClass($prefix . 'ajaxCountryField');
     //important, otherwise loadData will override the default value....
     $this->{$name} = EcommerceCountry::get_country();
     return $countryField;
 }
コード例 #22
0
 /**
  * sets country in order so that modifiers can be recalculated, etc...
  * @param String - $countryCode
  * @return Boolean
  **/
 public function setCountry($countryCode)
 {
     if (EcommerceCountry::code_allowed($countryCode)) {
         $this->currentOrder()->SetCountryFields($countryCode);
         $this->addMessage(_t("ShoppingCart.UPDATEDCOUNTRY", "Updated country."), 'good');
         return true;
     } else {
         $this->addMessage(_t("ShoppingCart.NOTUPDATEDCOUNTRY", "Could not update country."), 'bad');
         return false;
     }
 }
コード例 #23
0
 /**
  * Used to save Name to database
  * @return String
  */
 protected function LiveName()
 {
     $finalString = _t("OrderModifier.TAXCOULDNOTBEDETERMINED", "tax could not be determined");
     $countryCode = $this->LiveCountry();
     $startString = '';
     $name = '';
     $endString = '';
     $taxObjects = $this->currentTaxObjects();
     if ($taxObjects) {
         $objectArray = array();
         foreach ($taxObjects as $object) {
             $objectArray[] = $object->Name;
         }
         if (count($objectArray)) {
             $name = implode(", ", $objectArray);
         }
         if ($this->config()->get("exclusive_explanation") && $this->isExclusive()) {
             $endString = $this->config()->get("exclusive_explanation");
         } elseif ($this->Config()->get("inclusive_explanation") && $this->isInclusive()) {
             $endString = $this->Config()->get("inclusive_explanation");
         }
         if ($name) {
             $finalString = $startString . $name . $endString;
         }
     } else {
         if ($this->hasExceptionTaxes()) {
             $finalString = $this->Config()->get("no_tax_description");
         }
     }
     if ($countryCode && $finalString) {
         $countryName = EcommerceCountry::find_title($countryCode);
         if ($this->Config()->get("based_on_country_note") && $countryName && $countryCode != self::get_default_country_code_combined()) {
             $finalString .= $this->Config()->get("based_on_country_note") . ' ' . $countryName;
         }
     }
     return $finalString;
 }